123456789_123456789_123456789_123456789_123456789_

Class: ActiveSupport::Cache::FileStore

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, Store
Instance Chain:
self, Store
Inherits: ActiveSupport::Cache::Store
Defined in: activesupport/lib/active_support/cache/file_store.rb

Overview

File Cache Store

A cache store implementation which stores everything on the filesystem.

Constant Summary

Store - Inherited

DEFAULT_POOL_OPTIONS

Class Attribute Summary

Store - Inherited

Class Method Summary

Store - Inherited

.new

Creates a new cache.

.retrieve_pool_options

Instance Attribute Summary

Instance Method Summary

Store - Inherited

#cleanup

Cleans up the cache by removing expired entries.

#clear

Clears the entire cache.

#decrement

Decrements an integer value in the cache.

#delete

Deletes an entry in the cache.

#delete_matched

Deletes all entries with keys matching the pattern.

#delete_multi

Deletes multiple entries in the cache.

#exist?

Returns true if the cache contains an entry for the given key.

#fetch

Fetches data from the cache, using the given key.

#fetch_multi

Fetches data from the cache, using the given keys.

#increment

Increments an integer value in the cache.

#mute

Silences the logger within a block.

#read

Reads data from the cache, using the given key.

#read_multi

Reads multiple values at once from the cache.

#silence,
#silence!

Silences the logger.

#write

Writes the value to the cache with the key.

#write_multi

::ActiveSupport::Cache Storage API to write multiple values at once.

#_instrument, #default_serializer,
#delete_entry

Deletes an entry from the cache implementation.

#delete_multi_entries

Deletes multiples entries in the cache implementation.

#deserialize_entry,
#expanded_key

Expands key to be a consistent string value.

#expanded_version, #get_entry_value, #handle_expired_entry, #handle_invalid_expires_in, #instrument, #instrument_multi,
#key_matcher

Adds the namespace defined in the options to a pattern designed to match keys.

#merged_options

Merges the default options with ones specific to a method call.

#namespace_key

Prefix the key with a namespace string:

#normalize_key

Expands and namespaces the cache key.

#normalize_options

Normalize aliased options to their canonical form.

#normalize_version,
#read_entry

Reads an entry from the cache implementation.

#read_multi_entries

Reads multiple entries from the cache implementation.

#save_block_result_to_cache, #serialize_entry, #validate_options,
#write_entry

Writes an entry to the cache implementation.

#write_multi_entries

Writes multiple entries to the cache implementation.

#new_entry

Constructor Details

.new(cache_path, **options) ⇒ FileStore

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 20

def initialize(cache_path, **options)
  super(options)
  @cache_path = cache_path.to_s
end

Class Attribute Details

.supports_cache_versioning?Boolean (readonly)

Advertise cache versioning support.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 26

def self.supports_cache_versioning?
  true
end

Instance Attribute Details

#cache_path (readonly)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 13

attr_reader :cache_path

Instance Method Details

#cleanup(options = nil)

Preemptively iterates through all stored keys and removes the ones which have expired.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 40

def cleanup(options = nil)
  options = merged_options(options)
  search_dir(cache_path) do |fname|
    entry = read_entry(fname, **options)
    delete_entry(fname, **options) if entry && entry.expired?
  end
end

#clear(options = nil)

Deletes all items from the cache. In this case it deletes all the entries in the specified file store directory except for .keep or .gitkeep. Be careful which directory is specified in your config file when using FileStore because everything in that directory will be deleted.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 33

def clear(options = nil)
  root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
  FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
rescue Errno::ENOENT, Errno::ENOTEMPTY
end

#decrement(name, amount = 1, options = nil)

Decrement a cached integer value. Returns the updated value.

If the key is unset, it will be set to -amount.

cache.decrement("foo") # => -1

To set a specific value, call #write:

cache.write("baz", 5)
cache.decrement("baz") # => 4
[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 80

def decrement(name, amount = 1, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:decrement, key, amount: amount) do
    modify_value(name, -amount, options)
  end
end

#delete_empty_directories(dir) (private)

Delete empty directories in the cache.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 195

def delete_empty_directories(dir)
  return if File.realpath(dir) == File.realpath(cache_path)
  if Dir.children(dir).empty?
    Dir.delete(dir) rescue nil
    delete_empty_directories(File.dirname(dir))
  end
end

#delete_entry(key, **options) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 131

def delete_entry(key, **options)
  if File.exist?(key)
    begin
      File.delete(key)
      delete_empty_directories(File.dirname(key))
      true
    rescue
      # Just in case the error was caused by another process deleting the file first.
      raise if File.exist?(key)
      false
    end
  else
    false
  end
end

#delete_matched(matcher, options = nil)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 89

def delete_matched(matcher, options = nil)
  options = merged_options(options)
  matcher = key_matcher(matcher, options)

  instrument(:delete_matched, matcher.inspect) do
    search_dir(cache_path) do |path|
      key = file_path_key(path)
      delete_entry(path, **options) if key.match(matcher)
    end
  end
end

#ensure_cache_path(path) (private)

Make sure a file path’s directories exist.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 204

def ensure_cache_path(path)
  FileUtils.makedirs(path) unless File.exist?(path)
end

#file_path_key(path) (private)

Translate a file path into a key.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 189

def file_path_key(path)
  fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last.delete(File::SEPARATOR)
  URI.decode_www_form_component(fname, Encoding::UTF_8)
end

#increment(name, amount = 1, options = nil)

Increment a cached integer value. Returns the updated value.

If the key is unset, it starts from 0:

cache.increment("foo") # => 1
cache.increment("bar", 100) # => 100

To set a specific value, call #write:

cache.write("baz", 5)
cache.increment("baz") # => 6
[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 60

def increment(name, amount = 1, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:increment, key, amount: amount) do
    modify_value(name, amount, options)
  end
end

#inspect

This method is for internal use only.
[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 101

def inspect # :nodoc:
  "#<#{self.class.name} cache_path=#{@cache_path}, options=#{@options.inspect}>"
end

#lock_file(file_name, &block) (private)

Lock a file for a block so only one process can modify it at a time.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 148

def lock_file(file_name, &block)
  if File.exist?(file_name)
    File.open(file_name, "r+") do |f|
      f.flock File::LOCK_EX
      yield
    ensure
      f.flock File::LOCK_UN
    end
  else
    yield
  end
end

#modify_value(name, amount, options) (private)

Modifies the amount of an integer value that is stored in the cache. If the key is not found it is created and set to amount.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 222

def modify_value(name, amount, options)
  options = merged_options(options)
  key = normalize_key(name, options)
  version = normalize_version(name, options)
  amount = Integer(amount)

  lock_file(key) do
    entry = read_entry(key, **options)

    if !entry || entry.expired? || entry.mismatched?(version)
      write(name, amount, options)
      amount
    else
      num = entry.value.to_i + amount
      entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
      write_entry(key, entry)
      num
    end
  end
end

#normalize_key(key, options) (private)

Translate a key into a file path.

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 162

def normalize_key(key, options)
  key = super
  fname = URI.encode_www_form_component(key)

  if fname.size > FILEPATH_MAX_SIZE
    fname = ActiveSupport::Digest.hexdigest(key)
  end

  hash = Zlib.adler32(fname)
  hash, dir_1 = hash.divmod(0x1000)
  dir_2 = hash.modulo(0x1000)

  # Make sure file name doesn't exceed file system limits.
  if fname.length < FILENAME_MAX_SIZE
    fname_paths = fname
  else
    fname_paths = []
    begin
      fname_paths << fname[0, FILENAME_MAX_SIZE]
      fname = fname[FILENAME_MAX_SIZE..-1]
    end until fname.blank?
  end

  File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, fname_paths)
end

#read_entry(key, **options) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 106

def read_entry(key, **options)
  if payload = read_serialized_entry(key, **options)
    entry = deserialize_entry(payload)
    entry if entry.is_a?(Cache::Entry)
  end
end

#read_serialized_entry(key) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 113

def read_serialized_entry(key, **)
  File.binread(key) if File.exist?(key)
rescue => error
  logger.error("FileStoreError (#{error}): #{error.message}") if logger
  nil
end

#search_dir(dir, &callback) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 208

def search_dir(dir, &callback)
  return if !File.exist?(dir)
  Dir.each_child(dir) do |d|
    name = File.join(dir, d)
    if File.directory?(name)
      search_dir(name, &callback)
    else
      callback.call name
    end
  end
end

#write_entry(key, entry, **options) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 120

def write_entry(key, entry, **options)
  write_serialized_entry(key, serialize_entry(entry, **options), **options)
end

#write_serialized_entry(key, payload, **options) (private)

[ GitHub ]

  
# File 'activesupport/lib/active_support/cache/file_store.rb', line 124

def write_serialized_entry(key, payload, **options)
  return false if options[:unless_exist] && File.exist?(key)
  ensure_cache_path(File.dirname(key))
  File.atomic_write(key, cache_path) { |f| f.write(payload) }
  true
end