method
default_serializer
v7.1.3.2 -
Show latest stable
-
0 notes -
Class: ActiveSupport::Cache::Store
- 1.0.0
- 1.1.6
- 1.2.6
- 2.0.3
- 2.1.0
- 2.2.1
- 2.3.8
- 3.0.0
- 3.0.9
- 3.1.0
- 3.2.1
- 3.2.8
- 3.2.13
- 4.0.2
- 4.1.8
- 4.2.1
- 4.2.7
- 4.2.9
- 5.0.0.1
- 5.1.7
- 5.2.3
- 6.0.0
- 6.1.3.1
- 6.1.7.7
- 7.0.0
- 7.1.3.2 (0)
- 7.1.3.4 (0)
- What's this?
default_serializer()
private
Hide source
# File activesupport/lib/active_support/cache.rb, line 762 def default_serializer case Cache.format_version when 6.1 ActiveSupport.deprecator.warn <<~EOM Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2. Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format for more information on how to upgrade. EOM Cache::SerializerWithFallback[:marshal_6_1] when 7.0 Cache::SerializerWithFallback[:marshal_7_0] when 7.1 Cache::SerializerWithFallback[:marshal_7_1] else raise ArgumentError, "Unrecognized ActiveSupport::Cache.format_version: #{Cache.format_version.inspect}" end end # Adds the namespace defined in the options to a pattern designed to # match keys. Implementations that support delete_matched should call # this method to translate a pattern that matches names into one that # matches namespaced keys. def key_matcher(pattern, options) # :doc: prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace] if prefix source = pattern.source if source.start_with?("^") source = source[1, source.length] else source = ".*#{source[0, source.length]}" end Regexp.new("^#{Regexp.escape(prefix)}:#{source}", pattern.options) else pattern end end # Reads an entry from the cache implementation. Subclasses must implement # this method. def read_entry(key, **options) raise NotImplementedError.new end # Writes an entry to the cache implementation. Subclasses must implement # this method. def write_entry(key, entry, **options) raise NotImplementedError.new end def serialize_entry(entry, **options) options = merged_options(options) if @coder_supports_compression && options[:compress] @coder.dump_compressed(entry, options[:compress_threshold]) else @coder.dump(entry) end end def deserialize_entry(payload, **) payload.nil? ? nil : @coder.load(payload) rescue DeserializationError nil end # Reads multiple entries from the cache implementation. Subclasses MAY # implement this method. def read_multi_entries(names, **options) names.each_with_object({}) do |name, results| key = normalize_key(name, options) entry = read_entry(key, **options) next unless entry version = normalize_version(name, options) if entry.expired? delete_entry(key, **options) elsif !entry.mismatched?(version) results[name] = entry.value end end end # Writes multiple entries to the cache implementation. Subclasses MAY # implement this method. def write_multi_entries(hash, **options) hash.each do |key, entry| write_entry key, entry, **options end end # Deletes an entry from the cache implementation. Subclasses must # implement this method. def delete_entry(key, **options) raise NotImplementedError.new end # Deletes multiples entries in the cache implementation. Subclasses MAY # implement this method. def delete_multi_entries(entries, **options) entries.count { |key| delete_entry(key, **options) } end # Merges the default options with ones specific to a method call. def merged_options(call_options) if call_options call_options = normalize_options(call_options) if call_options.key?(:expires_in) && call_options.key?(:expires_at) raise ArgumentError, "Either :expires_in or :expires_at can be supplied, but not both" end expires_at = call_options.delete(:expires_at) call_options[:expires_in] = (expires_at - Time.now) if expires_at if call_options[:expires_in].is_a?(Time) expires_in = call_options[:expires_in] raise ArgumentError.new("expires_in parameter should not be a Time. Did you mean to use expires_at? Got: #{expires_in}") end if call_options[:expires_in]&.negative? expires_in = call_options.delete(:expires_in) handle_invalid_expires_in("Cache expiration time is invalid, cannot be negative: #{expires_in}") end if options.empty? call_options else options.merge(call_options) end else options end end def handle_invalid_expires_in(message) error = ArgumentError.new(message) if ActiveSupport::Cache::Store.raise_on_invalid_cache_expiration_time raise error else ActiveSupport.error_reporter&.report(error, handled: true, severity: :warning) logger.error("#{error.class}: #{error.message}") if logger end end # Normalize aliased options to their canonical form def normalize_options(options) options = options.dup OPTION_ALIASES.each do |canonical_name, aliases| alias_key = aliases.detect { |key| options.key?(key) } options[canonical_name] ||= options[alias_key] if alias_key options.except!(*aliases) end options end def validate_options(options) if options.key?(:coder) && options[:serializer] raise ArgumentError, "Cannot specify :serializer and :coder options together" end if options.key?(:coder) && options[:compressor] raise ArgumentError, "Cannot specify :compressor and :coder options together" end if Cache.format_version < 7.1 && !options[:serializer] && options[:compressor] raise ArgumentError, "Cannot specify :compressor option when using" " default serializer and cache format version is < 7.1" end options end # Expands and namespaces the cache key. # Raises an exception when the key is +nil+ or an empty string. # May be overridden by cache stores to do additional normalization. def normalize_key(key, options = nil) str_key = expanded_key(key) raise(ArgumentError, "key cannot be blank") if !str_key || str_key.empty? namespace_key str_key, options end # Prefix the key with a namespace string: # # namespace_key 'foo', namespace: 'cache' # # => 'cache:foo' # # With a namespace block: # # namespace_key 'foo', namespace: -> { 'cache' } # # => 'cache:foo' def namespace_key(key, options = nil) options = merged_options(options) namespace = options[:namespace] if namespace.respond_to?(:call) namespace = namespace.call end if key && key.encoding != Encoding::UTF_8 key = key.dup.force_encoding(Encoding::UTF_8) end if namespace "#{namespace}:#{key}" else key end end # Expands key to be a consistent string value. Invokes +cache_key+ if # object responds to +cache_key+. Otherwise, +to_param+ method will be # called. If the key is a Hash, then keys will be sorted alphabetically. def expanded_key(key) return key.cache_key.to_s if key.respond_to?(:cache_key) case key when Array if key.size > 1 key.collect { |element| expanded_key(element) } else expanded_key(key.first) end when Hash key.collect { |k, v| "#{k}=#{v}" }.sort! else key end.to_param end def normalize_version(key, options = nil) (options && options[:version].try(:to_param)) || expanded_version(key) end def expanded_version(key) case when key.respond_to?(:cache_version) then key.cache_version.to_param when key.is_a?(Array) then key.map { |element| expanded_version(element) }.tap(&:compact!).to_param when key.respond_to?(:to_a) then expanded_version(key.to_a) end end def instrument(operation, key, options = nil, &block) _instrument(operation, key: key, options: options, &block) end def instrument_multi(operation, keys, options = nil, &block) _instrument(operation, multi: true, key: keys, options: options, &block) end def _instrument(operation, multi: false, options: nil, **payload, &block) if logger && logger.debug? && !silence? debug_key = if multi ": #{payload[:key].size} key(s) specified" elsif payload[:key] ": #{normalize_key(payload[:key], options)}" end debug_options = " (#{options.inspect})" unless options.blank? logger.debug "Cache #{operation}#{debug_key}#{debug_options}" end payload[:store] = self.class.name payload.merge!(options) if options.is_a?(Hash) ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) do block&.call(payload) end end def handle_expired_entry(entry, key, options) if entry && entry.expired? race_ttl = options[:race_condition_ttl].to_i if (race_ttl > 0) && (Time.now.to_f - entry.expires_at <= race_ttl) # When an entry has a positive :race_condition_ttl defined, put the stale entry back into the cache # for a brief period while the entry is being recalculated. entry.expires_at = Time.now.to_f + race_ttl write_entry(key, entry, expires_in: race_ttl * 2) else delete_entry(key, **options) end entry = nil end entry end def get_entry_value(entry, name, options) instrument(:fetch_hit, name, options) entry.value end def save_block_result_to_cache(name, options) options = options.dup result = instrument(:generate, name, options) do yield(name, WriteOptions.new(options)) end write(name, result, options) unless result.nil? && options[:skip_nil] result end end # Enables the dynamic configuration of Cache entry options while ensuring # that conflicting options are not both set. When a block is given to # ActiveSupport::Cache::Store#fetch, the second argument will be an # instance of +WriteOptions+. class WriteOptions def initialize(options) # :nodoc: @options = options end def version @options[:version] end def version=(version) @options[:version] = version end def expires_in @options[:expires_in] end # Sets the Cache entry's +expires_in+ value. If an +expires_at+ option was # previously set, this will unset it since +expires_in+ and +expires_at+ # cannot both be set. def expires_in=(expires_in) @options.delete(:expires_at) @options[:expires_in] = expires_in end def expires_at @options[:expires_at] end # Sets the Cache entry's +expires_at+ value. If an +expires_in+ option was # previously set, this will unset it since +expires_at+ and +expires_in+ # cannot both be set. def expires_at=(expires_at) @options.delete(:expires_in) @options[:expires_at] = expires_at end end end