Class: Sprockets::Cache::FileStore

Inherits:
Object
  • Object
show all
Defined in:
lib/sprockets/cache/file_store.rb

Overview

Public: A file system cache store that automatically cleans up old keys.

Assign the instance to the Environment#cache.

environment.cache = Sprockets::Cache::FileStore.new("/tmp")

See Also

ActiveSupport::Cache::FileStore

Constant Summary collapse

DEFAULT_MAX_SIZE =

Internal: Default key limit for store.

25 * 1024 * 1024

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root, max_size = DEFAULT_MAX_SIZE, logger = self.class.default_logger) ⇒ FileStore

Public: Initialize the cache store.

root - A String path to a directory to persist cached values to. max_size - A Integer of the maximum number of keys the store will hold.

(default: 1000).


36
37
38
39
40
41
42
# File 'lib/sprockets/cache/file_store.rb', line 36

def initialize(root, max_size = DEFAULT_MAX_SIZE, logger = self.class.default_logger)
  @root     = root
  @size     = find_caches.inject(0) { |n, (_, stat)| n + stat.size }
  @max_size = max_size
  @gc_size  = max_size * 0.75
  @logger   = logger
end

Class Method Details

.default_loggerObject

Internal: Default standard error fatal logger.

Returns a Logger.



25
26
27
28
29
# File 'lib/sprockets/cache/file_store.rb', line 25

def self.default_logger
  logger = Logger.new($stderr)
  logger.level = Logger::FATAL
  logger
end

Instance Method Details

#get(key) ⇒ Object

Public: Retrieve value from cache.

This API should not be used directly, but via the Cache wrapper API.

key - String cache key.

Returns Object or nil or the value is not set.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/sprockets/cache/file_store.rb', line 51

def get(key)
  path = File.join(@root, "#{key}.cache")

  value = safe_open(path) do |f|
    begin
      EncodingUtils.unmarshaled_deflated(f.read, Zlib::MAX_WBITS)
    rescue Exception => e
      @logger.error do
        "#{self.class}[#{path}] could not be unmarshaled: " +
          "#{e.class}: #{e.message}"
      end
      nil
    end
  end

  if value
    FileUtils.touch(path)
    value
  end
end

#inspectObject

Public: Pretty inspect

Returns String.



121
122
123
# File 'lib/sprockets/cache/file_store.rb', line 121

def inspect
  "#<#{self.class} size=#{@size}/#{@max_size}>"
end

#set(key, value) ⇒ Object

Public: Set a key and value in the cache.

This API should not be used directly, but via the Cache wrapper API.

key - String cache key. value - Object value.

Returns Object value.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/sprockets/cache/file_store.rb', line 80

def set(key, value)
  path = File.join(@root, "#{key}.cache")

  # Ensure directory exists
  FileUtils.mkdir_p File.dirname(path)

  # Check if cache exists before writing
  exists = File.exist?(path)

  # Serialize value
  marshaled = Marshal.dump(value)

  # Compress if larger than 4KB
  if marshaled.bytesize > 4 * 1024
    deflater = Zlib::Deflate.new(
      Zlib::BEST_COMPRESSION,
      Zlib::MAX_WBITS,
      Zlib::MAX_MEM_LEVEL,
      Zlib::DEFAULT_STRATEGY
    )
    deflater << marshaled
    raw = deflater.finish
  else
    raw = marshaled
  end

  # Write data
  PathUtils.atomic_write(path) do |f|
    f.write(raw)
    @size += f.size unless exists
  end

  # GC if necessary
  gc! if @size > @max_size

  value
end