[Slim-Checkins] r10502 - in /trunk/server:
Plugins/Podcast/Plugin.pm Plugins/RssNews.pm
Slim/Player/Protocols/MMS.pm Slim/Utils/Cache.pm Slim/Utils/Scanner.pm
Slim/Web/Graphics.pm Slim/Web/HTTP.pm slimserver.pl
adrian at svn.slimdevices.com
adrian at svn.slimdevices.com
Sun Oct 29 09:37:27 PST 2006
Author: adrian
Date: Sun Oct 29 09:37:17 2006
New Revision: 10502
URL: http://svn.slimdevices.com?rev=10502&view=rev
Log:
Bug: 4432
Description: reduce impact of FileCache purging:
- support multiple namespaces with FileCache and purging them one at a time
- version number per cache so you can bump the version and force cleaning out of the old entries
- callers of new can create namespaces and decide whether they should be periodically purged
- all caches are purged once at startup
- follow on purges are only done if all players are off
Modified:
trunk/server/Plugins/Podcast/Plugin.pm
trunk/server/Plugins/RssNews.pm
trunk/server/Slim/Player/Protocols/MMS.pm
trunk/server/Slim/Utils/Cache.pm
trunk/server/Slim/Utils/Scanner.pm
trunk/server/Slim/Web/Graphics.pm
trunk/server/Slim/Web/HTTP.pm
trunk/server/slimserver.pl
Modified: trunk/server/Plugins/Podcast/Plugin.pm
URL: http://svn.slimdevices.com/trunk/server/Plugins/Podcast/Plugin.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Plugins/Podcast/Plugin.pm (original)
+++ trunk/server/Plugins/Podcast/Plugin.pm Sun Oct 29 09:37:17 2006
@@ -265,7 +265,7 @@
};
my $cache = Slim::Utils::Cache->new();
- $cache->set( 'podcasts_opml', $opml );
+ $cache->set( 'podcasts_opml', $opml, '10days' );
}
# for configuring via web interface
Modified: trunk/server/Plugins/RssNews.pm
URL: http://svn.slimdevices.com/trunk/server/Plugins/RssNews.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Plugins/RssNews.pm (original)
+++ trunk/server/Plugins/RssNews.pm Sun Oct 29 09:37:17 2006
@@ -242,7 +242,7 @@
};
my $cache = Slim::Utils::Cache->new();
- $cache->set( 'rss_opml', $opml );
+ $cache->set( 'rss_opml', $opml, '10days' );
}
# for configuring via web interface
Modified: trunk/server/Slim/Player/Protocols/MMS.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Player/Protocols/MMS.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Slim/Player/Protocols/MMS.pm (original)
+++ trunk/server/Slim/Player/Protocols/MMS.pm Sun Oct 29 09:37:17 2006
@@ -135,7 +135,7 @@
my $mmsURL = $url;
$mmsURL =~ s/^http/mms/;
- my $cache = Slim::Utils::Cache->instance;
+ my $cache = Slim::Utils::Cache->new;
my $streamNum = $cache->get( 'wma_streamNum_' . $mmsURL );
my $wma = $cache->get( 'wma_metadata_' . $mmsURL );
@@ -173,7 +173,7 @@
my $mmsURL = $url;
$mmsURL =~ s/^http/mms/;
- my $cache = Slim::Utils::Cache->instance;
+ my $cache = Slim::Utils::Cache->new;
my $streamNum = $cache->get( 'wma_streamNum_' . $mmsURL );
setMetadata( $client, $url, $wma, $streamNum || 1 );
Modified: trunk/server/Slim/Utils/Cache.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Utils/Cache.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Slim/Utils/Cache.pm (original)
+++ trunk/server/Slim/Utils/Cache.pm Sun Oct 29 09:37:17 2006
@@ -12,7 +12,7 @@
=head1 SYNOPSIS
-my $cache = Slim::Utils::Cache->new
+my $cache = Slim::Utils::Cache->new($namespace, $version, $noPeriodicPurge)
$cache->set($file, $data);
@@ -28,7 +28,13 @@
=head1 METHODS
-=head2 new()
+=head2 new( [ $namespeace ], [ $version ], [ $noPeriodicPurge ] )
+
+$namespace allows unique namespace for cache to give control of purging on per namespace basis
+
+$version - version number of cache content, first new call with different version number empties existing cache
+
+$noPeriodicPurge - set for namespaces expecting large caches so purging only happens at startup
Creates a new Slim::Utils::Cache instance.
@@ -39,7 +45,6 @@
=cut
use strict;
-use base qw(Class::Singleton);
use Cache::FileCache ();
@@ -48,26 +53,70 @@
use Slim::Utils::Prefs;
use Slim::Utils::Timers;
-my $PURGE_INTERVAL = 3600;
+my $DEFAULT_EXPIRES_TIME = '1 hour';
+
+my $PURGE_INTERVAL = 60 * 60 * 24; # interval between purge cycles
+my $PURGE_RETRY = 60 * 60; # retry time if players are on
+my $PURGE_NEXT = 30; # purge next namespace
+
+my $defaultNameSpace = 'FileCache';
+my $defaultVersion = 1;
+
+# hash of caches which we have created by namespace
+my %caches = ();
+
+my @thisCycle = (); # namespaces to be purged this purge cycle
+my @eachCycle = (); # namespaces to be purged every PURGE_INTERVAL
+
+my $startUpPurge = 1; # Flag for purging at startup
+
+my $log = logger('server');
+
+# create proxy methods
+{
+ my @methods = qw(
+ get set get_object set_object
+ clear purge remove size
+ );
+
+ no strict 'refs';
+ for my $method (@methods) {
+ *{ __PACKAGE__ . "::$method" } = sub {
+ return shift->{_cache}->$method(@_);
+ };
+ }
+}
sub init {
my $class = shift;
-
- # Clean up the cache at startup
- __PACKAGE__->new->purge();
-
- # And continue to clean it up regularly
- Slim::Utils::Timers::setTimer( undef, time() + $PURGE_INTERVAL, \&cleanup );
-}
-
-sub new { shift->instance(@_) }
-
-sub _new_instance {
+
+ # cause the default cache to be created if it is not already
+ __PACKAGE__->new();
+
+ # start purge routine in 10 seconds to purge all caches created during server and plugin startup
+ Slim::Utils::Timers::setTimer( undef, time() + 10, \&cleanup );
+}
+
+sub new {
my $class = shift;
-
+ my $namespace = shift || $defaultNameSpace;
+
+ # return existing instance if exists for this namespace
+ return $caches{$namespace} if $caches{$namespace};
+
+ # otherwise create new cache object taking acount of additional params
+ my ($version, $noPeriodicPurge);
+
+ if ($namespace eq $defaultNameSpace) {
+ $version = $defaultVersion;
+ } else {
+ $version = shift || 0;
+ $noPeriodicPurge = shift;
+ }
+
my $cache = Cache::FileCache->new( {
- namespace => 'FileCache',
- default_expires_in => $Cache::FileCache::EXPIRES_NEVER,
+ namespace => $namespace,
+ default_expires_in => $DEFAULT_EXPIRES_TIME,
cache_root => Slim::Utils::Prefs::get('cachedir'),
directory_umask => umask(),
} );
@@ -76,58 +125,85 @@
_cache => $cache,
}, $class;
- # create proxy methods
- {
- my @methods = qw(
- get set get_object set_object
- clear purge remove size
- );
-
- no strict 'refs';
- for my $method (@methods) {
- *{"$class\::$method"} = sub {
- return shift->{_cache}->$method(@_);
- };
+ # empty existing cache if version number is different
+ my $cacheVersion = $self->get('Slim::Utils::Cache-version');
+
+ unless (defined $cacheVersion && $cacheVersion eq $version) {
+
+ $log->info("Version changed for cache: $namespace - clearing out old entries");
+ $self->clear();
+ $self->set('Slim::Utils::Cache-version', $version, 'never');
+
+ }
+
+ # store cache object and add namespace to purge lists
+ $caches{$namespace} = $self;
+ push @thisCycle, $namespace;
+ push @eachCycle, $namespace unless $noPeriodicPurge;
+
+ return $self;
+}
+
+sub cleanup {
+ # This routine purges the complete list of namespaces, one per timer call
+ # NB Purging is expensive and blocks the server
+ #
+ # namespaces with $noPeriodicPurge set are only purged at server startup
+ # others are purged at max once per $PURGE_INTERVAL.
+ #
+ # To allow disks to spin down, each namespace is purged within a short period
+ # and then no purging is done for $PURGE_INTERVAL
+ #
+ # After the startup purge, if any players are on it reschedules in $PURGE_RETRY
+
+ my $namespace; # namespace to purge this call
+ my $interval; # interval to next call
+
+ # take one namespace from list to purge this cycle
+ $namespace = shift @thisCycle;
+
+ # after startup don't purge if a player is on - retry later
+ unless ($startUpPurge) {
+ for my $client ( Slim::Player::Client::clients() ) {
+ if ($client->power()) {
+ unshift @thisCycle, $namespace;
+ $namespace = undef;
+ $interval = $PURGE_RETRY;
+ last;
+ }
}
}
-
- return $self;
-}
-
-sub cleanup {
-
- # Use the same method the Scheduler uses to run only when idle
- my $busy;
- my $log = logger('server');
-
- for my $client ( Slim::Player::Client::clients() ) {
-
- if (Slim::Player::Source::playmode($client) eq 'play' &&
- $client->isPlayer() &&
- $client->usage() < 0.5) {
-
- $busy = 1;
- last;
+
+ unless ($interval) {
+ if (@thisCycle) {
+ $interval = $startUpPurge ? 0.1 : $PURGE_NEXT;
+ } else {
+ $interval = $PURGE_INTERVAL;
+ $startUpPurge = 0;
+ push @thisCycle, @eachCycle;
}
}
- if ( !$busy ) {
-
- $log->info("Cleaning up expired items...");
-
- __PACKAGE__->new->purge();
-
- $log->info("Done");
-
- Slim::Utils::Timers::setTimer( undef, time() + $PURGE_INTERVAL, \&cleanup );
- }
- else {
-
- # try again soon
- $log->info("Skipping cache cleanup, server is busy.");
-
- Slim::Utils::Timers::setTimer( undef, time() + ($PURGE_INTERVAL / 6), \&cleanup );
- }
-}
+ my $now = Time::HiRes::time();
+
+ if ($namespace && $caches{$namespace}) {
+
+ my $cache = $caches{$namespace};
+ my $lastpurge = $cache->get('Slim::Utils::Cache-purgetime');
+
+ unless ($lastpurge && ($now - $lastpurge) < $PURGE_INTERVAL) {
+ my $start = $now;
+ $cache->purge;
+ $cache->set('Slim::Utils::Cache-purgetime', $start, 'never');
+ $now = Time::HiRes::time();
+ $log->info(sprintf("Cache purge: $namespace - %f sec", $now - $start));
+ } else {
+ $log->info("Cache purge: $namespace - skipping, purged recently");
+ }
+ }
+
+ Slim::Utils::Timers::setTimer( undef, $now + $interval, \&cleanup );
+}
+
1;
Modified: trunk/server/Slim/Utils/Scanner.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Utils/Scanner.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Slim/Utils/Scanner.pm (original)
+++ trunk/server/Slim/Utils/Scanner.pm Sun Oct 29 09:37:17 2006
@@ -1083,7 +1083,7 @@
$mmsURL =~ s/^http/mms/;
# Cache this metadata for the MMS protocol handler to use
- my $cache = Slim::Utils::Cache->instance;
+ my $cache = Slim::Utils::Cache->new;
$cache->set( 'wma_streamNum_' . $mmsURL, $streamNum, '1 day' );
$cache->set( 'wma_metadata_' . $mmsURL, $wma, '1 day' );
Modified: trunk/server/Slim/Web/Graphics.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Graphics.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Slim/Web/Graphics.pm (original)
+++ trunk/server/Slim/Web/Graphics.pm Sun Oct 29 09:37:17 2006
@@ -16,9 +16,12 @@
my $log = logger('artwork');
-{
+my $canUseGD = 0;
+my $cache;
+
+sub init {
# Artwork resizing support by using GD, requires JPEG support built in
- my $canUseGD = eval {
+ $canUseGD = eval {
require GD;
if (GD::Image->can('jpeg')) {
return 1;
@@ -27,9 +30,12 @@
}
};
- sub serverResizesArt {
- return $canUseGD;
- }
+ # create cache for artwork which is not purged periodically due to potential size of cache
+ $cache = Slim::Utils::Cache->new('Artwork', 1, 1);
+}
+
+sub serverResizesArt {
+ return $canUseGD;
}
sub processCoverArtRequest {
@@ -88,7 +94,7 @@
$log->info(" artwork cache key: $cacheKey");
- $cachedImage = Slim::Utils::Cache->new()->get($cacheKey);
+ $cachedImage = $cache->get($cacheKey);
if ($cachedImage && $cachedImage->{'mtime'} != $obj->coverArtMtime($image)) {
$cachedImage = undef;
@@ -106,7 +112,7 @@
$cacheKey = "BLANK-$resizeMode-$requestedWidth-$requestedHeight-$requestedBackColour";
- $cachedImage = Slim::Utils::Cache->new()->get($cacheKey);
+ $cachedImage = $cache->get($cacheKey);
unless ($cachedImage) {
@@ -125,7 +131,7 @@
$log->info(" got cover art image $contentType of ". length($imageData) . " bytes");
- if (serverResizesArt() && $typeToMethod{$contentType}) {
+ if ($canUseGD && $typeToMethod{$contentType}) {
# If this is a thumb, a size has been given, or this is a png and the background color isn't 100% transparent
# then the overhead of loading the image with GD is necessary. Otherwise, the original content
@@ -311,7 +317,7 @@
$log->info(" caching result key: $cacheKey");
- Slim::Utils::Cache->new()->set($cacheKey, $cached, "10days");
+ $cache->set($cacheKey, $cached, "10days");
}
return ($body, $mtime, $inode, $size, $contentType);
Modified: trunk/server/Slim/Web/HTTP.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/HTTP.pm?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/Slim/Web/HTTP.pm (original)
+++ trunk/server/Slim/Web/HTTP.pm Sun Oct 29 09:37:17 2006
@@ -131,6 +131,9 @@
# Initialize all the web page handlers.
Slim::Web::Pages::init();
+
+ # Initialize graphics resizing
+ Slim::Web::Graphics::init();
# if we've got an HTTP port specified, open it up!
if (Slim::Utils::Prefs::get('httpport')) {
Modified: trunk/server/slimserver.pl
URL: http://svn.slimdevices.com/trunk/server/slimserver.pl?rev=10502&r1=10501&r2=10502&view=diff
==============================================================================
--- trunk/server/slimserver.pl (original)
+++ trunk/server/slimserver.pl Sun Oct 29 09:37:17 2006
@@ -338,8 +338,8 @@
$log->info("Async Networking init...");
Slim::Networking::Async->init;
- $log->info("Cache init, cleaning up FileCache...");
- Slim::Utils::Cache->init;
+ $log->info("Cache init...");
+ Slim::Utils::Cache->init();
if (!$noupnp) {
$log->info("UPnP init...");
More information about the checkins
mailing list