line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CHI::Cascade; |
2
|
|
|
|
|
|
|
|
3
|
15
|
|
|
15
|
|
1983279
|
use strict; |
|
15
|
|
|
|
|
86
|
|
|
15
|
|
|
|
|
441
|
|
4
|
15
|
|
|
15
|
|
78
|
use warnings; |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
572
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = 0.300_004; |
7
|
|
|
|
|
|
|
|
8
|
15
|
|
|
15
|
|
84
|
use Carp; |
|
15
|
|
|
|
|
30
|
|
|
15
|
|
|
|
|
966
|
|
9
|
|
|
|
|
|
|
|
10
|
15
|
|
|
15
|
|
3631
|
use CHI::Cascade::Value ':state'; |
|
15
|
|
|
|
|
46
|
|
|
15
|
|
|
|
|
2617
|
|
11
|
15
|
|
|
15
|
|
6646
|
use CHI::Cascade::Rule; |
|
15
|
|
|
|
|
39
|
|
|
15
|
|
|
|
|
485
|
|
12
|
15
|
|
|
15
|
|
6235
|
use CHI::Cascade::Target; |
|
15
|
|
|
|
|
42
|
|
|
15
|
|
|
|
|
416
|
|
13
|
15
|
|
|
15
|
|
91
|
use Time::HiRes (); |
|
15
|
|
|
|
|
31
|
|
|
15
|
|
|
|
|
191
|
|
14
|
15
|
|
|
15
|
|
7953
|
use POSIX (); |
|
15
|
|
|
|
|
128935
|
|
|
15
|
|
|
|
|
49689
|
|
15
|
|
|
|
|
|
|
|
16
|
0
|
0
|
|
0
|
0
|
0
|
sub min ($$) { $_[0] < $_[1] ? $_[0] : $_[1] } |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub new { |
19
|
1
|
|
|
1
|
1
|
131283
|
my ($class, %opts) = @_; |
20
|
|
|
|
|
|
|
|
21
|
1
|
|
33
|
|
|
48
|
my $self = bless { |
22
|
|
|
|
|
|
|
%opts, |
23
|
|
|
|
|
|
|
plain_targets => {}, |
24
|
|
|
|
|
|
|
qr_targets => [], |
25
|
|
|
|
|
|
|
stats => { recompute => 0, run => 0, dependencies_lookup => 0 } |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
}, ref($class) || $class; |
28
|
|
|
|
|
|
|
|
29
|
1
|
|
33
|
|
|
30
|
$self->{target_chi} ||= $self->{chi}; |
30
|
|
|
|
|
|
|
|
31
|
1
|
|
|
|
|
6
|
$self; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub rule { |
35
|
3
|
|
|
3
|
1
|
1277
|
my ($self, %opts) = @_; |
36
|
|
|
|
|
|
|
|
37
|
3
|
|
|
|
|
44
|
my $rule = CHI::Cascade::Rule->new( cascade => $self, %opts ); |
38
|
|
|
|
|
|
|
|
39
|
3
|
100
|
|
|
|
15
|
if (ref($rule->{target}) eq 'Regexp') { |
|
|
50
|
|
|
|
|
|
40
|
1
|
|
|
|
|
12
|
push @{ $self->{qr_targets} }, $rule; |
|
1
|
|
|
|
|
9
|
|
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
elsif (! ref($rule->{target})) { |
43
|
2
|
|
|
|
|
11
|
$self->{plain_targets}{$rule->{target}} = $rule; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
else { |
46
|
0
|
|
|
|
|
0
|
croak qq{The rule's target "$rule->{target}" is unknown type}; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub target_computing { |
51
|
29
|
|
|
29
|
0
|
43
|
my $trg_obj; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
( $trg_obj = $_[0]->{target_chi}->get("t:$_[1]") ) |
54
|
29
|
50
|
|
|
|
126
|
? ( ( ${ $_[2] } = $trg_obj->ttl ), $trg_obj->locked ? 1 : 0 ) |
|
25
|
100
|
|
|
|
78
|
|
55
|
|
|
|
|
|
|
: 0; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub target_is_actual { |
59
|
6
|
|
|
6
|
0
|
17
|
my ( $self, $target, $actual_term ) = @_; |
60
|
|
|
|
|
|
|
|
61
|
6
|
|
|
|
|
10
|
my $trg_obj; |
62
|
|
|
|
|
|
|
|
63
|
6
|
100
|
|
|
|
39
|
( $trg_obj = $self->{target_chi}->get("t:$target") ) |
64
|
|
|
|
|
|
|
? $trg_obj->is_actual( $actual_term ) |
65
|
|
|
|
|
|
|
: 0; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub target_time { |
69
|
40
|
|
|
40
|
0
|
76
|
my ($self, $target) = @_; |
70
|
|
|
|
|
|
|
|
71
|
40
|
|
|
|
|
64
|
my $trg_obj; |
72
|
|
|
|
|
|
|
|
73
|
40
|
100
|
|
|
|
136
|
return ( ( $trg_obj = $self->{target_chi}->get("t:$target") ) |
74
|
|
|
|
|
|
|
? $trg_obj->time |
75
|
|
|
|
|
|
|
: 0 |
76
|
|
|
|
|
|
|
); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub get_value { |
80
|
11
|
|
|
11
|
0
|
25
|
my ($self, $target) = @_; |
81
|
|
|
|
|
|
|
|
82
|
11
|
|
|
|
|
40
|
my $value = $self->{chi}->get("v:$target"); |
83
|
|
|
|
|
|
|
|
84
|
11
|
50
|
|
|
|
3662
|
return $value->state( CASCADE_FROM_CACHE ) |
85
|
|
|
|
|
|
|
if ($value); |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
0
|
CHI::Cascade::Value->new( state => CASCADE_NO_CACHE ); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub target_lock { |
91
|
11
|
|
|
11
|
0
|
649
|
my ( $self, $rule ) = @_; |
92
|
|
|
|
|
|
|
|
93
|
11
|
|
|
|
|
34
|
my $target = $rule->target; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# If target is already locked - a return |
96
|
|
|
|
|
|
|
return |
97
|
11
|
100
|
|
|
|
50
|
if ( $self->target_locked( $rule ) ); |
98
|
|
|
|
|
|
|
|
99
|
8
|
|
|
|
|
18
|
my $trg_obj; |
100
|
|
|
|
|
|
|
$trg_obj = CHI::Cascade::Target->new |
101
|
8
|
100
|
|
|
|
29
|
unless ( ( $trg_obj = $self->{target_chi}->get("t:$target") ) ); |
102
|
|
|
|
|
|
|
|
103
|
8
|
|
|
|
|
1180
|
$trg_obj->lock; |
104
|
8
|
|
|
|
|
35
|
$self->{target_chi}->set( "t:$target", $trg_obj, $rule->target_expires( $trg_obj ) ); |
105
|
|
|
|
|
|
|
|
106
|
8
|
|
|
|
|
7170
|
$rule->{run_instance}{target_locks}{$target} = 1; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub target_unlock { |
110
|
8
|
|
|
8
|
0
|
17
|
my ( $self, $rule, $value ) = @_; |
111
|
|
|
|
|
|
|
|
112
|
8
|
|
|
|
|
19
|
my $target = $rule->target; |
113
|
|
|
|
|
|
|
|
114
|
8
|
50
|
|
|
|
63
|
if ( my $trg_obj = $self->{target_chi}->get( "t:$target" ) ) { |
115
|
8
|
|
|
|
|
2502
|
$trg_obj->unlock; |
116
|
|
|
|
|
|
|
|
117
|
8
|
50
|
33
|
|
|
42
|
if ( $value && $value->state & CASCADE_RECOMPUTED ) { |
118
|
8
|
|
|
|
|
34
|
$trg_obj->touch; |
119
|
|
|
|
|
|
|
$trg_obj->actual_stamp |
120
|
8
|
100
|
66
|
|
|
42
|
if $rule->{run_instance}{run_opts}{actual_term} && $rule->{run_instance}{orig_target} eq $target; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
8
|
|
|
|
|
30
|
$self->{target_chi}->set( "t:$target", $trg_obj, $rule->target_expires( $trg_obj ) ); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
8
|
|
|
|
|
16798
|
delete $rule->{run_instance}{target_locks}{$target}; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub target_actual_stamp { |
130
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $rule, $value ) = @_; |
131
|
|
|
|
|
|
|
|
132
|
0
|
|
|
|
|
0
|
my $target = $rule->target; |
133
|
|
|
|
|
|
|
|
134
|
0
|
0
|
0
|
|
|
0
|
if ( $value && $value->state & CASCADE_ACTUAL_VALUE && ( my $trg_obj = $self->{target_chi}->get( "t:$target" ) ) ) { |
|
|
|
0
|
|
|
|
|
135
|
0
|
|
|
|
|
0
|
$trg_obj->actual_stamp; |
136
|
0
|
|
|
|
|
0
|
$self->{target_chi}->set( "t:$target", $trg_obj, $rule->target_expires( $trg_obj ) ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub target_start_ttl { |
141
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $rule, $start_time ) = @_; |
142
|
|
|
|
|
|
|
|
143
|
0
|
|
|
|
|
0
|
my $target = $rule->target; |
144
|
|
|
|
|
|
|
|
145
|
0
|
0
|
|
|
|
0
|
if ( my $trg_obj = $self->{target_chi}->get( "t:$target" ) ) { |
146
|
0
|
|
|
|
|
0
|
$trg_obj->ttl( $rule->ttl, $start_time ); |
147
|
0
|
|
|
|
|
0
|
$self->{target_chi}->set( "t:$target", $trg_obj, $rule->target_expires( $trg_obj ) ); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub target_remove { |
152
|
0
|
|
|
0
|
1
|
0
|
my ($self, $target) = @_; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
0
|
$self->{target_chi}->remove("t:$target"); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub touch { |
158
|
2
|
|
|
2
|
1
|
12
|
my ( $self, $target ) = @_; |
159
|
|
|
|
|
|
|
|
160
|
2
|
50
|
|
|
|
25
|
if ( my $trg_obj = $self->{target_chi}->get("t:$target") ) { |
161
|
2
|
|
|
|
|
974
|
$trg_obj->touch; |
162
|
2
|
|
|
|
|
14
|
$self->{target_chi}->set( "t:$target", $trg_obj, $self->find( $target )->target_expires( $trg_obj ) ); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub target_locked { |
167
|
91
|
|
|
91
|
0
|
199
|
my ( $self, $rule ) = @_; |
168
|
|
|
|
|
|
|
|
169
|
91
|
|
|
|
|
227
|
exists $rule->{run_instance}{target_locks}{ $rule->target }; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub recompute { |
173
|
8
|
|
|
8
|
0
|
33
|
my ( $self, $rule, $target, $dep_values) = @_; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
die CHI::Cascade::Value->new( state => CASCADE_DEFERRED ) |
176
|
8
|
50
|
|
|
|
27
|
if $rule->{run_instance}{run_opts}{defer}; |
177
|
|
|
|
|
|
|
|
178
|
8
|
|
|
|
|
13
|
my $ret = eval { $rule->{code}->( $rule, $target, $rule->{dep_values} = $dep_values ) }; |
|
8
|
|
|
|
|
36
|
|
179
|
|
|
|
|
|
|
|
180
|
8
|
|
|
|
|
71
|
$self->{stats}{recompute}++; |
181
|
|
|
|
|
|
|
|
182
|
8
|
50
|
|
|
|
19
|
if ($@) { |
183
|
0
|
|
|
|
|
0
|
my $error = $@; |
184
|
0
|
0
|
|
|
|
0
|
die( ( eval { $error->isa('CHI::Cascade::Value') } ) ? $error->thrown_from_code(1) : "CHI::Cascade: the target $target - error in the code: $error" ); |
|
0
|
|
|
|
|
0
|
|
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
8
|
|
|
|
|
10
|
my $value; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# For performance a value should not expire in anyway (only target marker if need) |
190
|
8
|
|
|
|
|
41
|
$self->{chi}->set( "v:$target", $value = CHI::Cascade::Value->new->value($ret), 'never' ); |
191
|
|
|
|
|
|
|
|
192
|
8
|
|
|
|
|
5586
|
$value->state( CASCADE_ACTUAL_VALUE | CASCADE_RECOMPUTED ); |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
$rule->{recomputed}->( $rule, $target, $value ) |
195
|
8
|
100
|
|
|
|
45
|
if ( ref $rule->{recomputed} eq 'CODE' ); |
196
|
|
|
|
|
|
|
|
197
|
8
|
|
|
|
|
72
|
return $value; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub value_ref_if_recomputed { |
201
|
29
|
|
|
29
|
0
|
70
|
my ( $self, $rule, $target, $only_from_cache ) = @_; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
return undef |
204
|
29
|
50
|
|
|
|
63
|
unless defined $rule; |
205
|
|
|
|
|
|
|
|
206
|
29
|
|
|
|
|
46
|
my $run_instance = $rule->{run_instance}; |
207
|
|
|
|
|
|
|
|
208
|
29
|
|
|
|
|
88
|
my @qr_params = $rule->qr_params; |
209
|
|
|
|
|
|
|
|
210
|
29
|
|
|
|
|
59
|
my ( $ret_state, $ttl, $should_be_recomputed ) = ( CASCADE_ACTUAL_VALUE ); |
211
|
|
|
|
|
|
|
|
212
|
29
|
50
|
|
|
|
86
|
if ( $self->target_computing( $target, \$ttl ) ) { |
213
|
|
|
|
|
|
|
# If we have any target as a being computed (dependencie/original) |
214
|
|
|
|
|
|
|
# there is no need to compute anything - trying to return original target value |
215
|
0
|
|
|
|
|
0
|
die CHI::Cascade::Value->new->state( CASCADE_COMPUTING ); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
29
|
|
|
|
|
996
|
my ( %dep_values, $dep_name ); |
219
|
|
|
|
|
|
|
|
220
|
29
|
100
|
|
|
|
66
|
if ( $only_from_cache ) { |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# Trying to get value from cache |
223
|
9
|
|
|
|
|
25
|
my $value = $self->get_value($target); |
224
|
|
|
|
|
|
|
|
225
|
9
|
50
|
|
|
|
22
|
return $value |
226
|
|
|
|
|
|
|
if $value->is_value; |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# If no in cache - we should recompute it again |
229
|
0
|
|
|
|
|
0
|
$self->target_lock($rule); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
20
|
|
|
|
|
37
|
push @{ $run_instance->{target_stack} }, $target; |
|
20
|
|
|
|
|
52
|
|
233
|
|
|
|
|
|
|
|
234
|
20
|
|
|
|
|
32
|
my $ret = eval { |
235
|
20
|
|
|
|
|
31
|
my $dep_target; |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
my $catcher = sub { |
238
|
17
|
|
|
17
|
|
29
|
my $sub = shift; |
239
|
|
|
|
|
|
|
|
240
|
17
|
|
|
|
|
69
|
my $ret = eval { $sub->() }; |
|
17
|
|
|
|
|
32
|
|
241
|
|
|
|
|
|
|
|
242
|
17
|
50
|
|
|
|
45
|
if ($@) { |
243
|
0
|
|
|
|
|
0
|
my $exception = $@; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
$rule->{depends_catch}->( $rule, $exception, $dep_values{$dep_target}->[0], $dep_target ) |
246
|
|
|
|
|
|
|
if ( exists $rule->{depends_catch} |
247
|
|
|
|
|
|
|
&& ref $rule->{depends_catch} eq 'CODE' |
248
|
0
|
0
|
0
|
|
|
0
|
&& eval { $exception->isa('CHI::Cascade::Value') } |
|
0
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
|
|
249
|
|
|
|
|
|
|
&& $exception->thrown_from_code ); |
250
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
0
|
die $exception; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
17
|
|
|
|
|
57
|
return $ret; |
255
|
20
|
|
|
|
|
110
|
}; |
256
|
|
|
|
|
|
|
|
257
|
20
|
100
|
|
|
|
61
|
$self->target_lock($rule) |
258
|
|
|
|
|
|
|
if ! $self->target_time($target); |
259
|
|
|
|
|
|
|
|
260
|
20
|
|
|
|
|
66
|
$should_be_recomputed = $self->target_locked($rule); |
261
|
|
|
|
|
|
|
|
262
|
20
|
50
|
33
|
|
|
77
|
if ( defined $ttl && $ttl > 0 && ! $should_be_recomputed ) { |
|
|
|
33
|
|
|
|
|
263
|
0
|
|
|
|
|
0
|
$ret_state = CASCADE_TTL_INVOLVED; |
264
|
0
|
|
|
|
|
0
|
$run_instance->{ttl} = $ttl; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
else { |
267
|
|
|
|
|
|
|
my ( |
268
|
20
|
50
|
|
|
|
51
|
$rule_ttl, |
269
|
|
|
|
|
|
|
$circle_hash, |
270
|
|
|
|
|
|
|
$start_time, |
271
|
|
|
|
|
|
|
$min_start_time |
272
|
|
|
|
|
|
|
) = ( |
273
|
|
|
|
|
|
|
$rule->ttl, |
274
|
|
|
|
|
|
|
$only_from_cache ? 'only_cache_chain' : 'chain' |
275
|
|
|
|
|
|
|
); |
276
|
|
|
|
|
|
|
|
277
|
20
|
|
|
|
|
41
|
foreach my $depend (@{ $rule->depends }) { |
|
20
|
|
|
|
|
52
|
|
278
|
11
|
50
|
|
|
|
27
|
$dep_target = ref($depend) eq 'CODE' ? $depend->( $rule, @qr_params ) : $depend; |
279
|
|
|
|
|
|
|
|
280
|
11
|
|
|
|
|
33
|
$dep_values{$dep_target}->[0] = $self->find( $dep_target, $rule->{run_instance} ); |
281
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
0
|
die "Found circle dependencies (trace: " . join( '->', @{ $run_instance->{target_stack} }, $dep_target ) . ") - aborted!" |
283
|
11
|
50
|
|
|
|
38
|
if ( exists $run_instance->{ $circle_hash }{$target}{$dep_target} ); |
284
|
|
|
|
|
|
|
|
285
|
11
|
|
|
|
|
23
|
$run_instance->{ $circle_hash }{$target}{$dep_target} = 1; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
$catcher->( sub { |
288
|
11
|
100
|
100
|
11
|
|
72
|
if ( ! $only_from_cache |
|
|
|
66
|
|
|
|
|
289
|
|
|
|
|
|
|
&& ( $start_time = ( $self->{stats}{dependencies_lookup}++, |
290
|
|
|
|
|
|
|
( $dep_values{$dep_target}->[1] = $self->value_ref_if_recomputed( $dep_values{$dep_target}->[0], $dep_target ) )->state & CASCADE_RECOMPUTED && Time::HiRes::time |
291
|
|
|
|
|
|
|
|| ( $start_time = $self->target_time($dep_target) ) > $self->target_time($target) && $start_time ) ) ) |
292
|
|
|
|
|
|
|
{ |
293
|
7
|
50
|
66
|
|
|
48
|
if ( ! $should_be_recomputed |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
294
|
|
|
|
|
|
|
&& ! defined $ttl |
295
|
|
|
|
|
|
|
&& defined $rule_ttl |
296
|
|
|
|
|
|
|
&& $rule_ttl > 0 |
297
|
|
|
|
|
|
|
&& ( $start_time + $rule_ttl ) > Time::HiRes::time ) |
298
|
|
|
|
|
|
|
{ |
299
|
0
|
0
|
|
|
|
0
|
$min_start_time = defined $min_start_time ? min( $start_time, $min_start_time ) : $start_time; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
else { |
302
|
7
|
|
|
|
|
23
|
$self->target_lock($rule); |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
} |
305
|
11
|
|
|
|
|
84
|
} ); |
306
|
|
|
|
|
|
|
|
307
|
11
|
|
|
|
|
102
|
delete $run_instance->{ $circle_hash }{$target}{$dep_target}; |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
|
310
|
20
|
50
|
|
|
|
58
|
if ( defined $min_start_time ) { |
311
|
0
|
|
|
|
|
0
|
$ret_state = CASCADE_TTL_INVOLVED; |
312
|
0
|
|
|
|
|
0
|
$self->target_start_ttl( $rule, $min_start_time ); |
313
|
0
|
|
|
|
|
0
|
$run_instance->{ttl} = $min_start_time + $rule_ttl - Time::HiRes::time; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
20
|
100
|
|
|
|
50
|
if ( $self->target_locked($rule) ) { |
318
|
|
|
|
|
|
|
# We should recompute this target |
319
|
|
|
|
|
|
|
# So we should recompute values for other dependencies |
320
|
8
|
|
|
|
|
26
|
foreach $dep_target (keys %dep_values) { |
321
|
7
|
100
|
66
|
|
|
45
|
if ( ! defined $dep_values{$dep_target}->[1] |
322
|
|
|
|
|
|
|
|| ! $dep_values{$dep_target}->[1]->is_value ) |
323
|
|
|
|
|
|
|
{ |
324
|
6
|
|
|
|
|
13
|
$self->{stats}{dependencies_lookup}++; |
325
|
|
|
|
|
|
|
$catcher->( sub { |
326
|
6
|
50
|
|
6
|
|
20
|
if ( ! ( $dep_values{$dep_target}->[1] = $self->value_ref_if_recomputed( $dep_values{$dep_target}->[0], $dep_target, 1 ) )->is_value ) { |
327
|
0
|
|
|
|
|
0
|
$self->target_remove($dep_target); |
328
|
0
|
|
|
|
|
0
|
return 1; |
329
|
|
|
|
|
|
|
} |
330
|
6
|
|
|
|
|
21
|
return 0; |
331
|
6
|
50
|
|
|
|
35
|
} ) == 1 && return undef; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
20
|
100
|
|
|
|
52
|
return $self->recompute( $rule, $target, { map { $_ => $dep_values{$_}->[1]->value } keys %dep_values } ) |
|
7
|
|
|
|
|
26
|
|
337
|
|
|
|
|
|
|
if $self->target_locked($rule); |
338
|
|
|
|
|
|
|
|
339
|
12
|
|
|
|
|
73
|
return CHI::Cascade::Value->new( state => $ret_state ); |
340
|
|
|
|
|
|
|
}; |
341
|
|
|
|
|
|
|
|
342
|
20
|
|
|
|
|
34
|
pop @{ $run_instance->{target_stack} }; |
|
20
|
|
|
|
|
43
|
|
343
|
|
|
|
|
|
|
|
344
|
20
|
|
|
|
|
32
|
my $e = $@; |
345
|
|
|
|
|
|
|
|
346
|
20
|
100
|
66
|
|
|
49
|
if ( $self->target_locked($rule) ) { |
|
|
50
|
66
|
|
|
|
|
347
|
8
|
|
|
|
|
28
|
$self->target_unlock( $rule, $ret ); |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
elsif ( $run_instance->{run_opts}{actual_term} && ! $only_from_cache && $run_instance->{orig_target} eq $target ) { |
350
|
0
|
|
|
|
|
0
|
$self->target_actual_stamp( $rule, $ret ); |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
20
|
50
|
|
|
|
61
|
die $e if $e; |
354
|
|
|
|
|
|
|
|
355
|
20
|
|
33
|
|
|
152
|
return $ret || CHI::Cascade::Value->new; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub stash { |
359
|
0
|
|
|
0
|
1
|
0
|
warn "The Cascade::stash method is deprecated! Please use the Cascade::Rule::stash method for this!\n"; |
360
|
0
|
0
|
0
|
|
|
0
|
exists $_[0]->{stash} && $_[0]->{stash} || die "The stash method from outside run method!" |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub run { |
364
|
12
|
|
|
12
|
1
|
452
|
my ( $self, $target, %opts ) = @_; |
365
|
|
|
|
|
|
|
|
366
|
12
|
|
|
|
|
37
|
my $view_dependencies = 1; |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# The run's instance parameters. This instance to be needed to give ability to run the run method from deep inside run calls. |
369
|
|
|
|
|
|
|
# It's for internal using. |
370
|
12
|
|
|
|
|
25
|
my $run_instance = {}; |
371
|
|
|
|
|
|
|
|
372
|
12
|
|
50
|
|
|
103
|
$run_instance->{stash} = $opts{stash} && ref $opts{stash} eq 'HASH' && $opts{stash} || {}; |
373
|
|
|
|
|
|
|
|
374
|
12
|
|
|
|
|
29
|
$run_instance->{run_opts} = \%opts; |
375
|
12
|
|
|
|
|
34
|
$run_instance->{ttl} = undef; |
376
|
12
|
|
|
|
|
26
|
$run_instance->{target_locks} = {}; |
377
|
|
|
|
|
|
|
|
378
|
12
|
|
100
|
|
|
56
|
$opts{actual_term} ||= $self->find($target)->{actual_term}; |
379
|
12
|
|
|
|
|
31
|
$self->{stats}{run}++; |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
# FIXME to delete in future. Now it's deprecated |
382
|
12
|
|
|
|
|
29
|
$self->{stash} = $run_instance->{stash}; |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
$view_dependencies = ! $self->target_is_actual( $target, $opts{actual_term} ) |
385
|
12
|
100
|
|
|
|
51
|
if ( $opts{actual_term} ); |
386
|
|
|
|
|
|
|
|
387
|
12
|
|
|
|
|
206
|
my $res = $self->_run( ! $view_dependencies, $target, $run_instance ); |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
$res->state( CASCADE_ACTUAL_TERM ) |
390
|
12
|
100
|
100
|
|
|
57
|
if ( $opts{actual_term} && ! $view_dependencies ); |
391
|
|
|
|
|
|
|
|
392
|
12
|
50
|
33
|
|
|
34
|
if ( defined $run_instance->{ttl} && $run_instance->{ttl} > 0 ) { |
393
|
0
|
|
|
|
|
0
|
$res->state( CASCADE_TTL_INVOLVED ); |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
0
|
|
|
|
|
0
|
${ $opts{ttl} } = $run_instance->{ttl} |
397
|
12
|
50
|
|
|
|
29
|
if ( $opts{ttl} ); |
398
|
|
|
|
|
|
|
|
399
|
6
|
|
|
|
|
13
|
${ $opts{state} } = $res->state |
400
|
12
|
100
|
|
|
|
34
|
if ( $opts{state} ); |
401
|
|
|
|
|
|
|
|
402
|
12
|
|
|
|
|
31
|
$res->value; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
sub _run { |
406
|
12
|
|
|
12
|
|
37
|
my ( $self, $only_from_cache, $target, $run_instance ) = @_; |
407
|
|
|
|
|
|
|
|
408
|
12
|
50
|
|
|
|
31
|
croak qq{The target ($target) for run should be string} if ref($target); |
409
|
12
|
50
|
|
|
|
62
|
croak qq{The target for run is empty} if $target eq ''; |
410
|
|
|
|
|
|
|
|
411
|
12
|
|
|
|
|
32
|
$run_instance->{chain} = {}; |
412
|
12
|
|
|
|
|
35
|
$run_instance->{only_cache_chain} = {}; |
413
|
12
|
|
|
|
|
29
|
$run_instance->{target_stack} = []; |
414
|
|
|
|
|
|
|
|
415
|
12
|
|
|
|
|
22
|
my $ret = eval { |
416
|
12
|
|
|
|
|
37
|
$run_instance->{orig_target} = $target; |
417
|
|
|
|
|
|
|
|
418
|
12
|
|
|
|
|
50
|
return $self->value_ref_if_recomputed( $run_instance->{orig_rule} = $self->find( $target, $run_instance ), $target, $only_from_cache ); |
419
|
|
|
|
|
|
|
}; |
420
|
|
|
|
|
|
|
|
421
|
12
|
|
|
|
|
25
|
my $terminated; |
422
|
|
|
|
|
|
|
|
423
|
12
|
50
|
|
|
|
27
|
if ( $terminated = $@ ) { |
424
|
0
|
|
|
|
|
0
|
$ret = $@; |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
die $ret |
427
|
0
|
0
|
|
|
|
0
|
unless eval { $ret->isa('CHI::Cascade::Value') }; |
|
0
|
|
|
|
|
0
|
|
428
|
|
|
|
|
|
|
|
429
|
0
|
0
|
|
|
|
0
|
$ret->state( CASCADE_CODE_EXCEPTION ) |
430
|
|
|
|
|
|
|
unless $ret->state; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
12
|
100
|
|
|
|
37
|
if ( ! $ret->is_value ) { |
434
|
2
|
|
|
|
|
5
|
my $from_cache = $self->get_value( $target ); |
435
|
|
|
|
|
|
|
|
436
|
2
|
50
|
33
|
|
|
18
|
return $from_cache->state( $ret->state ) |
437
|
|
|
|
|
|
|
if ( $terminated || $from_cache->is_value ); |
438
|
|
|
|
|
|
|
|
439
|
0
|
0
|
|
|
|
0
|
return $self->_run( 1, $target, $run_instance ) |
440
|
|
|
|
|
|
|
if ! $only_from_cache; |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
10
|
|
|
|
|
23
|
return $ret; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub find { |
447
|
34
|
|
|
34
|
0
|
71
|
my ($self, $plain_target, $run_instance) = @_; |
448
|
|
|
|
|
|
|
|
449
|
34
|
50
|
|
|
|
83
|
die "CHI::Cascade::find : got empty target\n" if $plain_target eq ''; |
450
|
|
|
|
|
|
|
|
451
|
34
|
|
|
|
|
45
|
my $new_rule; |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# If target is flat text |
454
|
34
|
100
|
|
|
|
88
|
if (exists $self->{plain_targets}{$plain_target}) { |
455
|
17
|
100
|
|
|
|
56
|
return $self->{plain_targets}{$plain_target} |
456
|
|
|
|
|
|
|
unless $run_instance; |
457
|
12
|
|
|
|
|
40
|
( $new_rule = $self->{plain_targets}{$plain_target}->new( run_instance => $run_instance ) )->{matched_target} = $plain_target; |
458
|
12
|
|
|
|
|
41
|
return $new_rule; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# If rule's target is Regexp type |
462
|
17
|
|
|
|
|
24
|
foreach my $rule (@{$self->{qr_targets}}) { |
|
17
|
|
|
|
|
55
|
|
463
|
17
|
|
|
|
|
26
|
my @qr_params; |
464
|
|
|
|
|
|
|
|
465
|
17
|
50
|
|
|
|
163
|
if (@qr_params = $plain_target =~ $rule->{target}) { |
466
|
17
|
100
|
|
|
|
60
|
return $rule |
467
|
|
|
|
|
|
|
unless $run_instance; |
468
|
11
|
|
|
|
|
50
|
( $new_rule = $rule->new( run_instance => $run_instance ) )->qr_params(@qr_params); |
469
|
11
|
|
|
|
|
22
|
$new_rule->{matched_target} = $plain_target; |
470
|
11
|
|
|
|
|
52
|
return $new_rule; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
} |
473
|
|
|
|
|
|
|
|
474
|
0
|
|
|
|
|
|
die "CHI::Cascade::find : cannot find the target $plain_target\n"; |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
1; |
479
|
|
|
|
|
|
|
__END__ |