use
Carp
qw(croak confess)
;
our
$VERSION
=
'0.12'
;
my
$CACHE_STATS_ON
= 0;
if
(
defined
$ENV
{PERL5SUBCONTRACTSTATS} &&
$ENV
{PERL5SUBCONTRACTSTATS} eq
'1'
) {
$CACHE_STATS_ON
= 1;
}
my
%CACHE_STATS
;
sub
_is_profiler_on {
return
$CACHE_STATS_ON
;
}
sub
_incr_miss {
$CACHE_STATS
{
$_
[0]}->{calls}++;
}
sub
_incr_hit {
$CACHE_STATS
{
$_
[0]}->{calls}++;
$CACHE_STATS
{
$_
[0]}->{hits}++;
}
sub
_incr_max_reached {
if
(
$CACHE_STATS
{
$_
[0]}->{cache}->{cache_size} == 1) {
$CACHE_STATS
{
$_
[0]}->{maxsize}++;
}
}
sub
_get_cache_stats_report {
my
$report
=
""
;
my
(
$cntfnc
,
$cnthit
,
$cntqry
,
$cntclr
) = (0,0,0,0);
my
$length
= 0;
foreach
my
$func
(
sort
keys
%CACHE_STATS
) {
$length
=
length
$func
if
(
length
$func
>
$length
);
}
$report
.=
"------------------------------------------------------\n"
;
$report
.=
"Statistics from Sub::Contract's function result cache:\n"
;
$report
.=
"\n"
;
foreach
my
$func
(
sort
keys
%CACHE_STATS
) {
my
$hits
=
$CACHE_STATS
{
$func
}->{hits};
my
$calls
=
$CACHE_STATS
{
$func
}->{calls};
my
$max
=
$CACHE_STATS
{
$func
}->{maxsize};
$max
= 0
if
(
$max
== -1);
$cntfnc
++;
$cnthit
+=
$hits
;
$cntqry
+=
$calls
;
$cntclr
+=
$max
;
if
(
$calls
) {
my
$rate
=
int
(1000
*$hits
/
$calls
)/10;
$report
.=
" "
.
sprintf
(
"%-"
.
$length
.
"s :"
,
$func
).
" $rate % hits (calls: $calls, hits: $hits, max size reached: $max)\n"
;
}
}
$report
.=
"\n"
;
$report
.=
" number of caches: $cntfnc\n"
;
$report
.=
" total calls: $cntqry\n"
;
$report
.=
" total hits: $cnthit\n"
;
$report
.=
" total max size reached: $cntclr\n"
;
$report
.=
"\n"
;
$report
.=
"------------------------------------------------------\n"
;
return
$report
;
}
END {
print
_get_cache_stats_report
if
(
$CACHE_STATS_ON
);
}
sub
cache {
my
(
$self
,
%args
) =
@_
;
my
$size
=
delete
$args
{size} || 10000;
croak
"cache() got unknown arguments: "
.Dumper(
%args
)
if
(
%args
);
croak
"size should be a number"
if
(!
defined
$size
||
$size
!~ /^\d+$/);
$self
->{cache} = new Sub::Contract::Cache(
namespace
=>
$self
->contractor,
size
=>
$size
);
if
(
$CACHE_STATS_ON
&& !
exists
$CACHE_STATS
{
$self
->contractor}) {
$CACHE_STATS
{
$self
->contractor} = {
calls
=> 0,
hits
=> 0,
maxsize
=> -1,
cache
=>
$self
->{cache} };
}
return
$self
;
}
sub
get_cache {
return
$_
->{cache};
}
sub
has_cache {
return
(
exists
$_
->{cache}) ? 1:0;
}
sub
clear_cache {
my
$self
=
shift
;
confess
"contract defines no cache"
if
(!
exists
$self
->{cache});
$self
->{cache}->clear;
return
$self
;
}
sub
add_to_cache {
my
(
$self
,
$args
,
$results
) =
@_
;
confess
"add_to_cache expects an array ref of arguments"
if
(!
defined
$args
||
ref
$args
ne
"ARRAY"
);
confess
"add_to_cache expects an array ref of results"
if
(!
defined
$results
||
ref
$results
ne
"ARRAY"
);
confess
"contract defines no cache"
if
(!
exists
$self
->{cache});
my
$key_array
=
join
(
":"
,
map
( { (
defined
$_
) ?
$_
:
"undef"
; }
"array"
,
@$args
) );
my
$key_scalar
=
join
(
":"
,
map
( { (
defined
$_
) ?
$_
:
"undef"
; }
"scalar"
,
@$args
) );
$self
->{cache}->set(
$key_array
,
$results
);
$self
->{cache}->set(
$key_scalar
,
$results
);
return
$self
;
}
1;