mirror of https://github.com/rails/rails
Merge pull request #42014 from Shopify/local-cache-rafactor-take-2
Refactor LocalCache to avoid calling Marshal.dump as much
This commit is contained in:
commit
84ba451520
|
@ -527,6 +527,10 @@ module ActiveSupport
|
|||
end
|
||||
end
|
||||
|
||||
def new_entry(value, options = nil) # :nodoc:
|
||||
Entry.new(value, **merged_options(options))
|
||||
end
|
||||
|
||||
# Deletes all entries with keys matching the pattern.
|
||||
#
|
||||
# Options are passed to the underlying cache implementation.
|
||||
|
@ -858,6 +862,14 @@ module ActiveSupport
|
|||
end
|
||||
end
|
||||
|
||||
def compressed? # :nodoc:
|
||||
defined?(@compressed)
|
||||
end
|
||||
|
||||
def local?
|
||||
false
|
||||
end
|
||||
|
||||
# Duplicates the value in a class. This is used by cache implementations that don't natively
|
||||
# serialize entries to protect against accidental cache modifications.
|
||||
def dup_value!
|
||||
|
@ -893,10 +905,6 @@ module ActiveSupport
|
|||
end
|
||||
end
|
||||
|
||||
def compressed?
|
||||
defined?(@compressed)
|
||||
end
|
||||
|
||||
def uncompress(value)
|
||||
Marshal.load(Zlib::Inflate.inflate(value))
|
||||
end
|
||||
|
|
|
@ -35,6 +35,78 @@ module ActiveSupport
|
|||
# Simple memory backed cache. This cache is not thread safe and is intended only
|
||||
# for serving as a temporary memory cache for a single thread.
|
||||
class LocalStore < Store
|
||||
class Entry # :nodoc:
|
||||
class << self
|
||||
def build(cache_entry)
|
||||
return if cache_entry.nil?
|
||||
return cache_entry if cache_entry.compressed?
|
||||
|
||||
value = cache_entry.value
|
||||
if value.is_a?(String)
|
||||
DupableEntry.new(cache_entry)
|
||||
elsif !value || value == true || value.is_a?(Numeric)
|
||||
new(cache_entry)
|
||||
else
|
||||
MutableEntry.new(cache_entry)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :value, :version
|
||||
attr_accessor :expires_at
|
||||
|
||||
def initialize(cache_entry)
|
||||
@value = cache_entry.value
|
||||
@expires_at = cache_entry.expires_at
|
||||
@version = cache_entry.version
|
||||
end
|
||||
|
||||
def local?
|
||||
true
|
||||
end
|
||||
|
||||
def compressed?
|
||||
false
|
||||
end
|
||||
|
||||
def mismatched?(version)
|
||||
@version && version && @version != version
|
||||
end
|
||||
|
||||
def expired?
|
||||
expires_at && expires_at <= Time.now.to_f
|
||||
end
|
||||
|
||||
def marshal_dump
|
||||
raise NotImplementedError, "LocalStore::Entry should never be serialized"
|
||||
end
|
||||
end
|
||||
|
||||
class DupableEntry < Entry # :nodoc:
|
||||
def initialize(_cache_entry)
|
||||
super
|
||||
unless @value.frozen?
|
||||
@value = @value.dup.freeze
|
||||
end
|
||||
end
|
||||
|
||||
def value
|
||||
@value.dup
|
||||
end
|
||||
end
|
||||
|
||||
class MutableEntry < Entry # :nodoc:
|
||||
def initialize(cache_entry)
|
||||
@payload = Marshal.dump(cache_entry.value)
|
||||
@expires_at = cache_entry.expires_at
|
||||
@version = cache_entry.version
|
||||
end
|
||||
|
||||
def value
|
||||
Marshal.load(@payload)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize
|
||||
super
|
||||
@data = {}
|
||||
|
@ -65,8 +137,7 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def write_entry(key, entry, **options)
|
||||
entry.dup_value!
|
||||
@data[key] = entry
|
||||
@data[key] = Entry.build(entry)
|
||||
true
|
||||
end
|
||||
|
||||
|
@ -75,10 +146,7 @@ module ActiveSupport
|
|||
end
|
||||
|
||||
def fetch_entry(key, options = nil) # :nodoc:
|
||||
entry = @data.fetch(key) { @data[key] = yield }
|
||||
dup_entry = entry.dup
|
||||
dup_entry&.dup_value!
|
||||
dup_entry
|
||||
@data.fetch(key) { @data[key] = Entry.build(yield) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -131,12 +199,12 @@ module ActiveSupport
|
|||
def read_entry(key, **options)
|
||||
if cache = local_cache
|
||||
hit = true
|
||||
value = cache.fetch_entry(key) do
|
||||
entry = cache.fetch_entry(key) do
|
||||
hit = false
|
||||
super
|
||||
end
|
||||
options[:event][:store] = cache.class.name if hit && options[:event]
|
||||
value
|
||||
entry
|
||||
else
|
||||
super
|
||||
end
|
||||
|
@ -162,7 +230,12 @@ module ActiveSupport
|
|||
local_cache.write_entry(key, entry, **options) if local_cache
|
||||
end
|
||||
|
||||
super
|
||||
|
||||
if entry.local?
|
||||
super(key, new_entry(entry.value, options), **options)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def delete_entry(key, **options)
|
||||
|
|
Loading…
Reference in New Issue