NAME
CHI - Unified cache handling interface
VERSION
version 0.59
SYNOPSIS
use CHI;
# Choose a standard driver
#
my $cache = CHI->new( driver => 'Memory', global => 1 );
my $cache = CHI->new( driver => 'RawMemory', global => 1 );
my $cache = CHI->new( driver => 'File',
root_dir => '/path/to/root'
);
my $cache = CHI->new( driver => 'FastMmap',
root_dir => '/path/to/root',
cache_size => '1k'
);
my $cache = CHI->new( driver => 'Memcached::libmemcached',
servers => [ "10.0.0.15:11211", "10.0.0.15:11212" ],
l1_cache => { driver => 'FastMmap', root_dir => '/path/to/root' }
);
my $cache = CHI->new( driver => 'DBI',
dbh => $dbh
);
my $cache = CHI->new( driver => 'BerkeleyDB',
root_dir => '/path/to/root'
);
# Create your own driver
#
my $cache = CHI->new( driver => '+My::Special::Driver', ... );
# Cache operations
#
my $customer = $cache->get($name);
if ( !defined $customer ) {
$customer = get_customer_from_db($name);
$cache->set( $name, $customer, "10 minutes" );
}
my $customer2 = $cache->compute($name2, "10 minutes", sub {
get_customer_from_db($name2)
});
$cache->remove($name);
DESCRIPTION
CHI provides a unified caching API, designed to assist a developer in
persisting data for a specified period of time.
The CHI interface is implemented by driver classes that support
fetching, storing and clearing of data. Driver classes exist or will
exist for the gamut of storage backends available to Perl, such as
memory, plain files, memory mapped files, memcached, and DBI.
CHI is intended as an evolution of DeWitt Clinton's Cache::Cache
package, adhering to the basic Cache API but adding new features and
addressing limitations in the Cache::Cache implementation.
FEATURES
* Easy to create new drivers
* Uniform support for namespaces
* Automatic serialization of keys and values
* Multilevel caches
* Probabilistic expiration and busy locks, to reduce cache miss
stampedes
* Optional logging and statistics collection of cache activity
AVAILABILITY OF DRIVERS
The following drivers are currently available as part of this
distribution:
* CHI::Driver::Memory - In-process memory based cache
* CHI::Driver::RawMemory - In-process memory based cache that stores
references directly instead of serializing/deep-copying
* CHI::Driver::File - File-based cache using one file per entry in a
multi-level directory structure
* CHI::Driver::FastMmap - Shared memory interprocess cache via mmap'ed
files
* CHI::Driver::Null - Dummy cache in which nothing is stored
* CHI::Driver::CacheCache - CHI wrapper for Cache::Cache
The following drivers are currently available as separate CPAN
distributions:
* CHI::Driver::Memcached - Distributed memory-based cache (works with
Cache::Memcached, Cache::Memcached::Fast, and
Cache::Memcached::libmemcached)
* CHI::Driver::DBI - Cache in any DBI-supported database
* CHI::Driver::BerkeleyDB - Cache in BerkeleyDB files
* CHI::Driver::Redis - Cache in Redis
* CHI::Driver::SharedMem - Cache in shared memory
This list is likely incomplete. A complete set of drivers can be found
on CPAN by searching for "CHI::Driver".
RELATION TO OTHER MODULES
Cache::Cache
CHI is intended as an evolution of DeWitt Clinton's Cache::Cache
package. It starts with the same basic API (which has proven durable
over time) but addresses some implementation shortcomings that cannot be
fixed in Cache::Cache due to backward compatibility concerns. In
particular:
Performance
Some of Cache::Cache's subclasses (e.g. Cache::FileCache) have been
justifiably criticized as inefficient. CHI has been designed from
the ground up with performance in mind, both in terms of general
overhead and in the built-in driver classes. Method calls are kept
to a minimum, data is only serialized when necessary, and metadata
such as expiration time is stored in packed binary format alongside
the data.
Ease of subclassing
New Cache::Cache subclasses can be tedious to create, due to a lack
of code refactoring, the use of non-OO package subroutines, and the
separation of "cache" and "backend" classes. With CHI, the goal is
to make the creation of new drivers as easy as possible, roughly the
same as writing a TIE interface to your data store. Concerns like
serialization and expiration options are handled by the driver base
class so that individual drivers don't have to worry about them.
Increased compatibility with cache implementations
Probably because of the reasons above, Cache::Cache subclasses were
never created for some of the most popular caches available on CPAN,
e.g. Cache::FastMmap and Cache::Memcached. CHI's goal is to be able
to support these and other caches with a minimum performance
overhead and minimum of glue code required.
Cache
The Cache distribution is another redesign and implementation of Cache,
created by Chris Leishman in 2003. Like CHI, it improves performance and
reduces the barrier to implementing new cache drivers. It breaks with
the Cache::Cache interface in a few ways that I considered
non-negotiable - for example, get/set do not serialize data, and
namespaces are an optional feature that drivers may decide not to
implement.
Cache::Memcached, Cache::FastMmap, etc.
CPAN sports a variety of full-featured standalone cache modules
representing particular backends. CHI does not reinvent these but simply
wraps them with an appropriate driver. For example,
CHI::Driver::Memcached and CHI::Driver::FastMmap are thin layers around
Cache::Memcached and Cache::FastMmap.
Of course, because these modules already work on their own, there will
be some overlap. Cache::FastMmap, for example, already has code to
serialize data and handle expiration times. Here's how CHI resolves
these overlaps.
Serialization
CHI handles its own serialization, passing a flat binary string to
the underlying cache backend. The notable exception is
CHI::Driver::RawMemory which does no serialization.
Expiration
CHI packs expiration times (as well as other metadata) inside the
binary string passed to the underlying cache backend. The backend is
unaware of these values; from its point of view the item has no
expiration time. Among other things, this means that you can use CHI
to examine expired items (e.g. with $cache->get_object) even if this
is not supported natively by the backend.
At some point CHI will provide the option of explicitly notifying
the backend of the expiration time as well. This might allow the
backend to do better storage management, etc., but would prevent CHI
from examining expired items.
Naturally, using CHI's FastMmap or Memcached driver will never be as
time or storage efficient as simply using Cache::FastMmap or
Cache::Memcached. In terms of performance, we've attempted to make the
overhead as small as possible, on the order of 5% per get or set
(benchmarks coming soon). In terms of storage size, CHI adds about 16
bytes of metadata overhead to each item. How much this matters obviously
depends on the typical size of items in your cache.
SUPPORT AND DOCUMENTATION
Questions and feedback are welcome, and should be directed to the
perl-cache mailing list:
http://groups.google.com/group/perl-cache-discuss
Bugs and feature requests will be tracked at RT:
http://rt.cpan.org/NoAuth/Bugs.html?Dist=CHI
bug-chi@rt.cpan.org
The latest source code can be browsed and fetched at:
http://github.com/jonswar/perl-chi/tree/master
git clone git://github.com/jonswar/perl-chi.git
ACKNOWLEDGMENTS
Thanks to Dewitt Clinton for the original Cache::Cache, to Rob Mueller
for the Perl cache benchmarks, and to Perrin Harkins for the discussions
that got this going.
CHI was originally designed and developed for the Digital Media group of
the Hearst Corporation, a diversified media company based in New York
City. Many thanks to Hearst management for agreeing to this open source
release.
SEE ALSO
Cache::Cache
AUTHOR
Jonathan Swartz <swartz@pobox.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2012 by Jonathan Swartz.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.