CGI-Ex-Recipes

 view release on metacpan or  search on metacpan

erecipes/perl/lib/CGI/Ex/Recipes/Cache.pm  view on Meta::CPAN

    0;
}

sub get {
    my ($self,$key) = @_;
    #dex_trace(); #debug $self;
    if(exists $self->{cache_hash}{$key}) {
        return $self->{cache_hash}{$key}{value};
    }
    #warn 'getting $key'.$key.' from database';
    my $row = $self->{dbh}->selectrow_hashref('SELECT * FROM cache WHERE id=?',{},$key) 
        || return undef;
    $self->{cache_hash}{$key} = $row;
    if($self->{cache_hash}{$key}{expires} < time ){
        #warn 'could not $key'.$key.' from database. data expired.';
        return undef;
    }
    return $self->{cache_hash}{$key}{value};
}

sub set {
    if (!$_[2]) { 
        croak 'Please provide a value to be set!';
    }
    #NOTE: compatible only with SQLITE and MySQL
    $_[0]->{dbh}->prepare(
        'REPLACE INTO `cache` (id, value, tstamp, expires) VALUES ( ?,?,?,? )'
    )->execute( $_[1], $_[2], time, ($_[3]?time+$_[3]:$_[0]->{expires}) );
}

sub clear {
    $_[0]->{cache_hash} = {};
    $_[0]->{dbh}->do('DELETE FROM `cache`')
        and $_[0]->{dbh}->do('VACUUM');

}

sub freeze {
    $_[0]->set( 
        $_[1], 
        ref $_[2] ? Storable::nfreeze($_[2]) : $_[2], 
        $_[3] || $_[0]->{expires},
    );
}

sub thaw {
    Storable::thaw( $_[0]->get($_[1]) ) ;
}


1;

__END__

=head1 NAME

CGI::Ex::Recipes::Cache - Naive caching in a database table

=head1 SYNOPSIS

Example from C<CGI::Ex::Recipes::Template::Menu::list_item()>:

    # ... somewhere at the beginning of a method/subroutine which does heavy computations
    if( $out = $app->cache->get($cache_key) ){ return $out; }
    # ... here are your heavy calculations spread accross many lines
    # making database calls generating HTML etc.
    # ... just before the return of the method
    #try cache support
    $app->cache->set($cache_key, $out);
    return $out;

=head1 DESCRIPTION

I found that when I cached in memory some output from CGI::Ex::Recipes::Template::Menu,
the performance under mod_perl jumped from: 

    ...
    Requests per second:    19.42 [#/sec] (mean)
    Time per request:       154.441 [ms] (mean)
    Time per request:       51.480 [ms] (mean, across all concurrent requests)
    Transfer rate:          67.73 [Kbytes/sec] received

to

    ...
    Requests per second:    42.99 [#/sec] (mean)
    Time per request:       69.792 [ms] (mean)
    Time per request:       23.264 [ms] (mean, across all concurrent requests)
    Transfer rate:          151.74 [Kbytes/sec] received

ApacheBench was invoked like this:

    berov@berovi:~> /opt/apache2/bin/ab -c3  -n300 http://localhost:8081/recipes/index.pl

Of cource this is copied and pasted from my shell. Your results will be different.

I searched CPAN and after realizing that there are too many alternatives I
decided to have some fun and write another one -- simple, stupid and naive.

After implementing my naive caching in a database table I have the following results:

    ...
    Requests per second:    58.35 [#/sec] (mean)
    Time per request:       51.418 [ms] (mean)
    Time per request:       17.139 [ms] (mean, across all concurrent requests)
    Transfer rate:          206.74 [Kbytes/sec] received

Not bad, I would say.

NOTE: 

    This module is not necessarily compatible with the L<Cache|Cache> interface nor near complete.

=head1 METHODS

head2 new

The constructor.

    our $cache_obj = CGI::Ex::Recipes::Cache->new(
        {cache_hash =>\%CACHE_HASH, dbh=>$dbh , expires =>3600*24 }
    );
    Arguments(a hashref):
        cache_hash: Applicaton-wide HASH reference.
                    useful only under mod_perl.
        dbh:        A DBI object.
        expires:    Default expiration for cache entries. Default:time + 3600(one hour)
    Returns:    $self - The cache object used in CGI::Ex::Recipes

=head2 exists

    my $bool = $cache->exists('somekey');

Checks for existence of a given key in C<$self-E<gt>{cache_hash}>.



( run in 0.680 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )