From ec93f363cab7270c1469b420a52a21e306a89c30 Mon Sep 17 00:00:00 2001 From: Brian Durand Date: Fri, 21 Oct 2011 13:28:24 -0500 Subject: [PATCH] Fix ActiveSupport::Cache::FileStore.cleanup to actually work. --- .../lib/active_support/cache/file_store.rb | 21 ++++++++++-- activesupport/test/caching_test.rb | 34 +++++++++++++++++++ .../guides/source/caching_with_rails.textile | 6 +++- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index b431041b76a1d..bc5d94b5a7e7c 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -26,11 +26,26 @@ def clear(options = nil) FileUtils.rm_r(root_dirs.collect{|f| File.join(cache_path, f)}) end + # Cleanup the cache by removing old entries. By default this will delete entries + # that haven't been accessed in one day. You can change this behavior by passing + # in a +not_accessed_in+ option. Any entry not accessed in that number of seconds + # in the past will be deleted. Alternatively, you can pass in +:expired_only+ with + # +true+ to only delete expired entries. def cleanup(options = nil) options = merged_options(options) - each_key(options) do |key| - entry = read_entry(key, options) - delete_entry(key, options) if entry && entry.expired? + expired_only = options[:expired_only] + timestamp = Time.now - (options[:not_accessed_in] || 1.day.to_i) + search_dir(cache_path) do |fname| + if expired_only + key = file_path_key(fname) + entry = read_entry(key, options) + delete_entry(key, options) if entry && entry.expired? + else + if File.atime(fname) <= timestamp + key = file_path_key(fname) + delete_entry(key, options) + end + end end end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index cb5362525f984..1b2f6d061c566 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -557,6 +557,29 @@ def test_key_transformation_with_pathname key = @cache_with_pathname.send(:key_file_path, "views/index?id=1") assert_equal "views/index?id=1", @cache_with_pathname.send(:file_path_key, key) end + + def test_cleanup_with_not_accessed_in + @cache.write(1, "aaaaaaaaaa") + @cache.write(2, "bbbbbbbbbb") + @cache.write(3, "cccccccccc") + sleep(2) + @cache.read(2) + @cache.cleanup(:not_accessed_in => 1) + assert_equal false, @cache.exist?(1) + assert_equal true, @cache.exist?(2) + assert_equal false, @cache.exist?(3) + end + + def test_cleanup_with_expired_only + @cache.write(1, "aaaaaaaaaa", :expires_in => 0.001) + @cache.write(2, "bbbbbbbbbb") + @cache.write(3, "cccccccccc", :expires_in => 0.001) + sleep(0.002) + @cache.cleanup(:expired_only => 0.001) + assert_equal false, @cache.exist?(1) + assert_equal true, @cache.exist?(2) + assert_equal false, @cache.exist?(3) + end # Because file systems have a maximum filename size, filenames > max size should be split in to directories # If filename is 'AAAAB', where max size is 4, the returned path should be AAAA/B @@ -646,6 +669,17 @@ def @cache.delete_entry (*args) assert_equal true, @cache.exist?(2) assert_equal false, @cache.exist?(1) end + + def test_cleanup_removes_expired_entries + @cache.write(1, "aaaaaaaaaa", :expires_in => 0.001) + @cache.write(2, "bbbbbbbbbb") + @cache.write(3, "cccccccccc", :expires_in => 0.001) + sleep(0.002) + @cache.cleanup + assert_equal false, @cache.exist?(1) + assert_equal true, @cache.exist?(2) + assert_equal false, @cache.exist?(3) + end end uses_memcached 'memcached backed store' do diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index 4273d0dd64ff1..721c791a33b89 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -289,7 +289,11 @@ ActionController::Base.cache_store = :file_store, "/path/to/cache/directory" With this cache store, multiple server processes on the same host can share a cache. Servers processes running on different hosts could share a cache by using a shared file system, but that set up would not be ideal and is not recommended. The cache store is appropriate for low to medium traffic sites that are served off one or two hosts. -Note that the cache will grow until the disk is full unless you periodically clear out old entries. +Note that the cache will grow until the disk is full unless you periodically clear out old entries. You can call +ActiveSupport::Cache::FileStore#cleanup+ to remove entries older than a specified time. + + +Rails.cache.cleanup(:not_accessed_in => 2.days) + h4. ActiveSupport::Cache::MemCacheStore