=head1 LICENSE Copyright (c) 1999-2013 The European Bioinformatics Institute and Genome Research Limited. All rights reserved. This software is distributed under a modified Apache license. For license details, please see http://www.ensembl.org/info/about/code_licence.html =head1 CONTACT Please email comments or questions to the public Ensembl developers list at . Questions may also be sent to the Ensembl help desk at . =cut =head1 NAME Bio::EnsEMBL::DBSQL::Support::LruIdCache - ID based caching using an LRU backed cache =head1 SYNOPSIS my $cache = Bio::EnsEMBL::DBSQL::Support::LruIdCache->new($adaptor, 2); my $obj = $cache->put(1, 'a'); my $obj = $cache->put(2, 'b'); my $obj = $cache->put(3, 'c'); is_deeply([$cache->cache_keys()], ['b','c']); #ID 1 was ejected under LRU rules =head1 DESCRIPTION An implementation of caching which uses the oldest accessed key as the value to be ejected from the cache when the maximum size has been hit. See the following page for more information about this algorithm http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used =head1 METHODS =cut package Bio::EnsEMBL::DBSQL::Support::LruIdCache; use strict; use warnings; use base qw/Bio::EnsEMBL::DBSQL::Support::BaseCache/; use Bio::EnsEMBL::Utils::Cache; use Bio::EnsEMBL::Utils::Scalar qw/assert_ref/; my $DEFAULT = 1000; =head2 new Arg [1] : Bio::EnsEMBL::DBSQL::BaseAdaptor $db_adaptor Arg [2] : Int size of the cache. Defaults to 1000 Example : my $cache = Bio::EnsEMBL::DBSQL::Support::LruIdCache->new($db_adaptor, 10); Description: Creates a new cache class instance Returntype : Bio::EnsEMBL::DBSQL::Support::BaseCache Exceptions : none Caller : BaseAdaptors Status : Beta =cut sub new { my ($class, $adaptor, $lru_size) = @_; my $self = $class->SUPER::new($adaptor); $lru_size ||= $DEFAULT; $self->lru_size($lru_size); return $self; } =head2 lru_size Arg [1] : Int size of the cache Example : $cache->lru_size(10); Description: Resets the size of the cache and forces a rebuild of the cache object to apply this new sizing. Also functions as a getter Returntype : Int Exceptions : none Caller : BaseAdaptors Status : Beta =cut sub lru_size { my ($self, $lru_size) = @_; if(defined $lru_size) { $self->{'lru_size'} = $lru_size; $self->delete_cache(); } return $self->{'lru_size'}; } =head2 build_cache Description: Returns an instance of C and sized according to the return value in C Returntype : Bio::EnsEMBL::Utils::Cache Exceptions : none Caller : BaseAdaptors Status : Beta =cut sub build_cache { my ($self) = @_; tie my %cache, 'Bio::EnsEMBL::Utils::Cache', $self->lru_size(); return \%cache; } =head2 get Arg [1] : String key to retrieve Example : $is($cache->get(1), 'a'); Description: Retrieves the value held in the cache. If the value is not in the cache we will retrieve the value from C<_uncached_fetch_by_dbID> and then store that value Returntype : Scalar value held in the cache or nothing if the ID was not present Exceptions : If key was undefined Caller : BaseAdaptors Status : Beta =cut sub get { my ($self, $key) = @_; my $value = $self->SUPER::get($key); if(! defined $value) { my $new_value = $self->adaptor()->_uncached_fetch_by_dbID($key); if(defined $new_value) { $self->put($key, $new_value); $value = $new_value; } } return $value if defined $value; return; } =head2 get_by_list Arg [1] : ArrayRef keys to retrieve Arg [2] : Bio::EnsEMBL::Slice optional attribute for C<_uncached_fetch_all_by_dbID_list()> delegation Example : is($cache->get_by_list([1,2]), ['a','b']); Description: Attempts to retreive all values currently available in the cache, fetches any remaining values and stores these in the cache. Returntype : ArrayRef of found values Exceptions : None Caller : BaseAdaptors Status : Beta =cut sub get_by_list { my ($self, $list, $slice) = @_; assert_ref($list, 'ARRAY', 'list'); my $results = $self->SUPER::get_by_list($list); my %available = map { $_->dbID(), $_ } @{$results}; my @to_fetch; foreach my $input (@{$list}) { next if ! defined $input; push(@to_fetch, $input) if ! exists $available{$input}; } my $fetched = $self->adaptor()->_uncached_fetch_all_by_dbID_list(\@to_fetch, $slice); foreach my $obj (@{$fetched}) { push(@{$results}, $obj); $self->put($obj->dbID(), $obj); } return $results; } 1;