Spec-Zone.ru › Ruby on Rails 8.1

класс ActiveSupport::Cache::Store

Родительский класс:
Object

Хранилище кэша Active Support

Абстрактный класс хранилища кэша. Существует несколько реализаций хранилищ кэша, каждая из которых имеет собственные дополнительные возможности. См. классы в модуле ActiveSupport::Cache, например ActiveSupport::Cache::MemCacheStore. В настоящее время MemCacheStore — самое популярное хранилище кэша для крупных рабочих веб-сайтов.

Некоторые реализации могут не поддерживать все методы, кроме основных методов работы с кэшем: fetch, write, read, exist? и delete.

ActiveSupport::Cache::Store может хранить любые объекты Ruby, поддерживаемые методами dump и load класса coder.

cache = ActiveSupport::Cache::MemoryStore.new

cache.read('city')   # => nil
cache.write('city', "Duckburgh") # => true
cache.read('city')   # => "Duckburgh"

cache.write('not serializable', Proc.new {}) # => TypeError

Ключи всегда преобразуются в строки, и регистр символов в них учитывается. Если в качестве ключа указан объект, у которого определён метод cache_key, этот метод будет вызван для формирования ключа. В противном случае будет вызван метод to_param. В качестве ключей также можно использовать хэши и массивы. Элементы будут разделены косыми чертами, а элементы внутри Hash будут отсортированы по ключу, чтобы обеспечить единообразие.

cache.read('city') == cache.read(:city)   # => true

Значения Nil можно кэшировать.

Если ваш кэш использует общую инфраструктуру, можно задать пространство имён для записей кэша. Если пространство имён задано, оно будет добавляться перед каждым ключом. Пространство имён может быть статическим значением или Proc. Если это Proc, он будет вызываться при вычислении каждого ключа, что позволит использовать логику приложения для аннулирования ключей.

cache.namespace = -> { @last_mod_time }  # Set the namespace to a variable
@last_mod_time = Time.now  # Invalidate the entire cache by changing namespace

Константы

DEFAULT_POOL_OPTIONS

Параметры ConnectionPool по умолчанию

MAX_KEY_SIZE

Если длина ключа превышает допустимый предел, он усекается с помощью дайджеста Active Support.

Атрибуты

options [R]
silence [R]
silence? [R]

Публичные методы класса

new (options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 300
def initialize(options = nil)
  @options = options ? validate_options(normalize_options(options)) : {}

  @options[:compress] = true unless @options.key?(:compress)
  @options[:compress_threshold] ||= DEFAULT_COMPRESS_LIMIT

  @max_key_size = @options.delete(:max_key_size)
  @max_key_size = MAX_KEY_SIZE if @max_key_size.nil? # allow 'false' as a value

  @coder = @options.delete(:coder) do
    legacy_serializer = Cache.format_version < 7.1 && !@options[:serializer]
    serializer = @options.delete(:serializer) || default_serializer
    serializer = Cache::SerializerWithFallback[serializer] if serializer.is_a?(Symbol)
    compressor = @options.delete(:compressor) { Zlib }

    Cache::Coder.new(serializer, compressor, legacy_serializer: legacy_serializer)
  end

  @coder ||= Cache::SerializerWithFallback[:passthrough]

  @coder_supports_compression = @coder.respond_to?(:dump_compressed)
end

Создаёт новое хранилище кэша.

Параметры

:namespace

Задаёт пространство имён для кэша. Этот параметр особенно полезен, если приложение использует кэш совместно с другими приложениями.

:serializer

Сериализатор кэшируемых значений. Должен отвечать на методы dump и load.

Сериализатор по умолчанию зависит от версии формата кэша (задаётся с помощью config.active_support.cache_format_version при использовании Rails). Сериализатор по умолчанию для каждой версии формата включает механизм резервной десериализации значений из любой версии формата. Это упрощает переход между версиями формата без аннулирования всего кэша.

Также можно указать serializer: :message_pack, чтобы использовать предварительно настроенный сериализатор на основе ActiveSupport::MessagePack. Сериализатор :message_pack включает тот же механизм резервной десериализации, упрощая переход с сериализатора по умолчанию или на него. Сериализатор :message_pack может повысить производительность, но для него требуется гем msgpack.

:compressor

Компрессор сериализованных значений кэша. Должен отвечать на методы deflate и inflate.

По умолчанию используется компрессор Zlib. Чтобы определить новый пользовательский компрессор, который также распаковывает старые записи кэша, можно проверять сжатые значения на наличие сигнатуры "\x78" из Zlib:

module MyCompressor
  def self.deflate(dumped)
    # compression logic... (make sure result does not start with "\x78"!)
  end

  def self.inflate(compressed)
    if compressed.start_with?("\x78")
      Zlib.inflate(compressed)
    else
      # decompression logic...
    end
  end
end

ActiveSupport::Cache.lookup_store(:redis_cache_store, compressor: MyCompressor)
:coder

Кодировщик для сериализации и (при необходимости) сжатия записей кэша. Должен отвечать на методы dump и load.

Кодировщик по умолчанию объединяет сериализатор и компрессор и включает несколько оптимизаций производительности. Если нужно переопределить только сериализатор или компрессор, следует указать параметры :serializer или :compressor соответственно.

Если хранилище может обрабатывать записи кэша напрямую, можно также указать coder: nil, чтобы не использовать сериализатор, компрессор и кодировщик. Например, если используется ActiveSupport::Cache::MemoryStore и можно гарантировать, что значения кэша не будут изменяться, укажите coder: nil, чтобы избежать дополнительных затрат на защиту от изменений.

Параметр :coder нельзя использовать вместе с параметрами :serializer и :compressor. Их совместное указание вызовет исключение ArgumentError.

Все остальные указанные параметры рассматриваются как параметры по умолчанию для соответствующих операций с кэшем, таких как read, write и fetch.

Публичные методы экземпляра

cleanup (options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 785
def cleanup(options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support cleanup")
end

Очищает кэш, удаляя просроченные записи.

Параметры передаются базовой реализации кэша.

Некоторые реализации могут не поддерживать этот метод.

clear (options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 795
def clear(options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support clear")
end

Полностью очищает кэш. Используйте этот метод с осторожностью: если кэш общий, это может повлиять на другие процессы.

Хэш параметров передаётся базовой реализации кэша.

Некоторые реализации могут не поддерживать этот метод.

decrement (name, amount = 1, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 750
def decrement(name, amount = 1, options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
end

Уменьшает целочисленное значение в кэше.

Параметры передаются базовой реализации кэша.

Некоторые реализации могут не поддерживать этот метод.

delete (name, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 686
def delete(name, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:delete, key, options) do
    delete_entry(key, **options)
  end
end

Удаляет запись из кэша. Возвращает true, если запись удалена, и false в противном случае.

Параметры передаются базовой реализации кэша.

delete_matched (matcher, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 732
def delete_matched(matcher, options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
end

Удаляет все записи с ключами, соответствующими шаблону.

Параметры передаются базовой реализации кэша.

Некоторые реализации могут не поддерживать этот метод.

delete_multi (names, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 699
def delete_multi(names, options = nil)
  return 0 if names.empty?

  options = merged_options(options)
  names.map! { |key| normalize_key(key, options) }

  instrument_multi(:delete_multi, names, options) do
    delete_multi_entries(names, **options)
  end
end

Удаляет несколько записей из кэша. Возвращает количество удалённых записей.

Параметры передаются базовой реализации кэша.

exist? (name, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 713
def exist?(name, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:exist?, key) do |payload|
    entry = read_entry(key, **options, event: payload)
    (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
  end
end

Возвращает true, если в кэше есть запись с указанным ключом.

Параметры передаются базовой реализации кэша.

fetch (name, options = nil, &block) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 452
def fetch(name, options = nil, &block)
  if block_given?
    options = merged_options(options)
    key = normalize_key(name, options)

    entry = nil
    unless options[:force]
      instrument(:read, key, options) do |payload|
        cached_entry = read_entry(key, **options, event: payload)
        entry = handle_expired_entry(cached_entry, key, options)
        if entry
          if entry.mismatched?(normalize_version(name, options))
            entry = nil
          else
            begin
              entry.value
            rescue DeserializationError
              entry = nil
            end
          end
        end
        payload[:super_operation] = :fetch if payload
        payload[:hit] = !!entry if payload
      end
    end

    if entry
      get_entry_value(entry, name, options)
    else
      save_block_result_to_cache(name, key, options, &block)
    end
  elsif options && options[:force]
    raise ArgumentError, "Missing block: Calling `Cache#fetch` with `force: true` requires a block."
  else
    read(name, options)
  end
end

Извлекает данные из кэша по указанному ключу. Если в кэше есть данные с таким ключом, они возвращаются.

Если таких данных в кэше нет (промах кэша), будет возвращено nil. Однако если передан блок, ему будет передан ключ, и блок будет выполнен при промахе кэша. Возвращаемое блоком значение будет записано в кэш под указанным ключом и возвращено.

cache.write('today', 'Monday')
cache.fetch('today')  # => "Monday"

cache.fetch('city')   # => nil
cache.fetch('city') do
  'Duckburgh'
end
cache.fetch('city')   # => "Duckburgh"

Параметры

Внутри fetch вызывает read_entry, а при промахе кэша — write_entry. Поэтому fetch поддерживает те же параметры, что и read и write. Кроме того, fetch поддерживает следующие параметры:

  • force: true — принудительно вызывает промах кэша: значение кэша считается отсутствующим, даже если оно есть. Если force имеет значение true, необходимо передать блок, чтобы в результате всегда выполнялась запись в кэш.

    cache.write('today', 'Monday')
    cache.fetch('today', force: true) { 'Tuesday' } # => 'Tuesday'
    cache.fetch('today', force: true) # => ArgumentError
    

    Параметр :force полезен, когда вы вызываете другой метод, чтобы определить, следует ли принудительно записать значение в кэш. В остальных случаях понятнее просто вызвать write.

  • skip_nil: true — предотвращает кэширование результата nil:

    cache.fetch('foo') { nil }
    cache.fetch('bar', skip_nil: true) { nil }
    cache.exist?('foo') # => true
    cache.exist?('bar') # => false
    
  • :race_condition_ttl — задаёт количество секунд, в течение которых просроченное значение можно повторно использовать, пока создаётся новое. Это позволяет избежать состязаний при истечении срока действия записей кэша и не допустить одновременной повторной генерации одной и той же записи несколькими процессами (также известной как эффект лавины запросов).

    Когда процесс обнаруживает запись кэша, срок действия которой истёк менее :race_condition_ttl секунд назад, он продлевает срок её действия на :race_condition_ttl секунд перед созданием нового значения. В течение этого дополнительного промежутка времени другие процессы продолжают использовать старое значение, пока первый процесс создаёт новое. После того как первый процесс запишет новое значение, остальные процессы начнут использовать его.

    Если при создании нового значения в первом процессе произойдёт ошибка, другой процесс сможет попытаться создать новое значение после истечения дополнительного промежутка времени.

    # Set all values to expire after one second.
    cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1)
    
    cache.write("foo", "original value")
    val_1 = nil
    val_2 = nil
    p cache.read("foo") # => "original value"
    
    sleep 1 # wait until the cache expires
    
    t1 = Thread.new do
      # fetch does the following:
      # 1. gets an recent expired entry
      # 2. extends the expiry by 2 seconds (race_condition_ttl)
      # 3. regenerates the new value
      val_1 = cache.fetch("foo", race_condition_ttl: 2) do
        sleep 1
        "new value 1"
      end
    end
    
    # Wait until t1 extends the expiry of the entry
    # but before generating the new value
    sleep 0.1
    
    val_2 = cache.fetch("foo", race_condition_ttl: 2) do
      # This block won't be executed because t1 extended the expiry
      "new value 2"
    end
    
    t1.join
    
    p val_1 # => "new value 1"
    p val_2 # => "original value"
    p cache.fetch("foo") # => "new value 1"
    
    # The entry requires 3 seconds to expire (expires_in + race_condition_ttl)
    # We have waited 2 seconds already (sleep(1) + t1.join) thus we need to wait 1
    # more second to see the entry expire.
    sleep 1
    
    p cache.fetch("foo") # => nil
    

Динамические параметры

В некоторых случаях может потребоваться динамически вычислять параметры на основе кэшированного значения. Для этого экземпляр ActiveSupport::Cache::WriteOptions передаётся блоку в качестве второго аргумента. Например:

cache.fetch("authentication-token:#{user.id}") do |key, options|
  token = authenticate_to_service
  options.expires_at = token.expires_at
  token
end
fetch_multi (*names) { |name| ... } Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 603
def fetch_multi(*names)
  raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
  return {} if names.empty?

  options = names.extract_options!
  options = merged_options(options)
  keys    = names.map { |name| normalize_key(name, options) }
  writes  = {}
  ordered = instrument_multi :read_multi, keys, options do |payload|
    if options[:force]
      reads = {}
    else
      reads = read_multi_entries(names, **options)
    end

    ordered = names.index_with do |name|
      reads.fetch(name) { writes[name] = yield(name) }
    end
    writes.compact! if options[:skip_nil]

    payload[:hits] = reads.keys.map { |name| normalize_key(name, options) }
    payload[:super_operation] = :fetch_multi

    ordered
  end

  write_multi(writes, options)

  ordered
end

Извлекает данные из кэша по указанным ключам. Если в кэше есть данные с указанными ключами, они возвращаются. В противном случае для каждого ключа, для которого данные отсутствуют, вызывается переданный блок, а его результат записывается в кэш и возвращается. Поэтому необходимо передать блок, возвращающий данные для записи в кэш. Если не нужно записывать данные в кэш при отсутствии значения, используйте read_multi.

Возвращает хэш с данными для каждого имени. Например:

cache.write("bim", "bam")
cache.fetch_multi("bim", "unknown_key") do |key|
  "Fallback value for key: #{key}"
end
# => { "bim" => "bam",
#      "unknown_key" => "Fallback value for key: unknown_key" }

Дополнительные параметры также можно указать с помощью аргумента options. Подробности см. в описании fetch. Остальные параметры передаются базовой реализации кэша. Например:

cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
  "buzz"
end
# => {"fizz"=>"buzz"}
cache.read("fizz")
# => "buzz"
sleep(6)
cache.read("fizz")
# => nil
increment (name, amount = 1, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 741
def increment(name, amount = 1, options = nil)
  raise NotImplementedError.new("#{self.class.name} does not support increment")
end

Увеличивает целочисленное значение в кэше.

Параметры передаются базовой реализации кэша.

Некоторые реализации могут не поддерживать этот метод.

mute () { || ... } Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 330
def mute
  previous_silence, @silence = @silence, true
  yield
ensure
  @silence = previous_silence
end

Отключает журналирование внутри блока.

namespace () Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 800
def namespace
  @options[:namespace]
end

Возвращает текущее пространство имён

namespace= (namespace) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 806
def namespace=(namespace)
  @options[:namespace] = namespace
end

Задаёт текущее пространство имён. Обратите внимание: это значение будет проигнорировано, если при вызовах методов кэша переданы пользовательские параметры с ключом пространства имён.

read (name, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 506
def read(name, options = nil)
  options = merged_options(options)
  key     = normalize_key(name, options)
  version = normalize_version(name, options)

  instrument(:read, key, options) do |payload|
    entry = read_entry(key, **options, event: payload)

    if entry
      if entry.expired?
        delete_entry(key, **options)
        payload[:hit] = false if payload
        nil
      elsif entry.mismatched?(version)
        payload[:hit] = false if payload
        nil
      else
        payload[:hit] = true if payload
        begin
          entry.value
        rescue DeserializationError
          payload[:hit] = false
          nil
        end
      end
    else
      payload[:hit] = false if payload
      nil
    end
  end
end

Читает данные из кэша по указанному ключу. Если в кэше есть данные с таким ключом, они возвращаются. В противном случае возвращается nil.

Обратите внимание: если данные были записаны с параметрами :expires_in или :version, оба этих условия проверяются до возврата данных.

Параметры

  • :namespace — заменяет пространство имён хранилища для этого вызова.

  • :version — задаёт версию записи кэша. Если версия в кэше не совпадает с запрошенной, чтение считается промахом кэша. Эта возможность используется для поддержки повторно используемых ключей кэша.

Обработка остальных параметров зависит от конкретной реализации хранилища кэша.

read_counter (name, **options) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 762
def read_counter(name, **options)
  options = merged_options(options).merge(raw: true)
  read(name, **options)&.to_i
end

Читает счётчик, заданный с помощью increment / decrement.

cache.write_counter("foo", 1)
cache.read_counter("foo") # => 1
cache.increment("foo")
cache.read_counter("foo") # => 2

Параметры передаются базовой реализации кэша.

read_multi (*names) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 544
def read_multi(*names)
  return {} if names.empty?

  options = names.extract_options!
  options = merged_options(options)
  keys    = names.map { |name| normalize_key(name, options) }

  instrument_multi :read_multi, keys, options do |payload|
    read_multi_entries(names, **options, event: payload).tap do |results|
      payload[:hits] = results.keys.map { |name| normalize_key(name, options) }
    end
  end
end

Одновременно читает из кэша несколько значений. Параметры можно передать последним аргументом.

Некоторые реализации кэша могут оптимизировать этот метод.

Возвращает хэш, сопоставляющий переданные имена найденным значениям.

silence! () Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 324
def silence!
  @silence = true
  self
end

Отключает журналирование.

write (name, value, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 672
def write(name, value, options = nil)
  options = merged_options(options)
  key = normalize_key(name, options)

  instrument(:write, key, options) do
    entry = Entry.new(value, **options, version: normalize_version(name, options))
    write_entry(key, entry, **options)
  end
end

Записывает значение в кэш по указанному ключу. Значение должно поддерживаться методами dump и load класса coder.

Возвращает true, если запись выполнена успешно, nil, если при обращении к серверной части кэша произошла ошибка, или false, если запись не удалась по другой причине.

По умолчанию записи кэша размером более 1 кБ сжимаются. Сжатие позволяет хранить больше данных в том же объёме памяти, сокращая количество вытеснений записей из кэша и повышая частоту попаданий в кэш.

Параметры

  • compress: false — отключает сжатие записи кэша.

  • :compress_threshold — порог сжатия в байтах. Записи кэша, размер которых превышает этот порог, будут сжаты. По умолчанию используется значение 1.kilobyte.

  • :expires_in — задаёт относительный срок действия записи кэша в секундах. :expire_in и :expired_in — псевдонимы для :expires_in.

    cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
    cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
    
  • :expires_at — задаёт абсолютное время истечения срока действия записи кэша.

    cache = ActiveSupport::Cache::MemoryStore.new
    cache.write(key, value, expires_at: Time.now.at_end_of_hour)
    
  • :version — задаёт версию записи кэша. При чтении из кэша, если версия в кэше не совпадает с запрошенной, чтение считается промахом кэша. Эта возможность используется для поддержки повторно используемых ключей кэша.

  • :unless_exist — предотвращает перезапись существующей записи кэша.

Обработка остальных параметров зависит от конкретной реализации хранилища кэша.

write_counter (name, value, **options) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 775
def write_counter(name, value, **options)
  options = merged_options(options).merge(raw: true)
  write(name, value.to_i, **options)
end

Записывает счётчик, который затем можно изменять с помощью increment / decrement.

cache.write_counter("foo", 1)
cache.read_counter("foo") # => 1
cache.increment("foo")
cache.read_counter("foo") # => 2

Параметры передаются базовой реализации кэша.

write_multi (hash, options = nil) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 559
def write_multi(hash, options = nil)
  return hash if hash.empty?

  options = merged_options(options)
  normalized_hash = hash.transform_keys { |key| normalize_key(key, options) }

  instrument_multi :write_multi, normalized_hash, options do |payload|
    entries = hash.each_with_object({}) do |(name, value), memo|
      memo[normalize_key(name, options)] = Entry.new(value, **options, version: normalize_version(name, options))
    end

    write_multi_entries entries, **options
  end
end

API хранилища Cache для одновременной записи нескольких значений.

Закрытые методы экземпляра

key_matcher (pattern, options) Показать исходный код
# File activesupport/lib/active_support/cache.rb, line 826
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

Добавляет пространство имён, заданное в параметрах, к шаблону для сопоставления ключей. Реализации, поддерживающие delete_matched, должны вызывать этот метод, чтобы преобразовать шаблон, соответствующий именам, в шаблон, соответствующий ключам с пространством имён.

© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API