Лучшие практики для реализации пользовательского кэширования?

17

Для каждого экземпляра каждого типа сущности я генерирую несколько кешей с именем вроде: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

Теперь, когда объект обновляется, я хочу удалить все кэши, начиная с соответствующего типа объекта и идентификатора.

Как мне хранить / очищать эти кэши?

В настоящее время я просто cache_set () , но возникает проблема, когда я хочу очистить, так как я не знаю имен всех соответствующих кэшей. Безопасно ли удалять записи в кеше с помощью db_delete ()?

Letharion
источник
Если вы не знаете имен всех соответствующих кэшей, как вы можете их использовать db_delete()?
kiamlaluno

Ответы:

6

Чтобы удалить записи из кэша, вы должны использовать cache_clear_all () . Причина в том, что используемая реализация кэша не смогла использовать таблицу базы данных в активной базе данных. Это то, что происходит с классом DrupalDatabaseCache , но это не должно быть верно для каждого класса.

Если вы посмотрите на _cache_get_object () (функцию, вызываемую cache_get () и cache_set () ), вы заметите, что она содержит следующий код.

  static $cache_objects; 
  if (!isset($cache_objects[$bin])) {
    $class = variable_get('cache_class_' . $bin);
    if (!isset($class)) {
      $class = variable_get('cache_default_class', 'DrupalDatabaseCache');
    }
    $cache_objects[$bin] = new $class($bin);
  }
  return $cache_objects[$bin];

Класс для реализации кеша может быть разным для каждого хранилища кеша, и даже класс по умолчанию может быть изменен.

Частная система кэширования состояния обновлений объясняет, почему обычные функции кэширования не используются в _update_cache_clear () , _update_cache_get () и _update_cache_set () . (Акцент мой.)

Мы специально НЕ используем API кеша ядра для сохранения выбранных данных о доступных обновлениях. Крайне важно, чтобы этот кэш очищался только тогда, когда мы заполняем его после успешного извлечения новых доступных данных обновления. Использование API-интерфейса основного кэша приводит к всевозможным потенциальным проблемам, которые могут привести к попытке извлечения доступных данных обновления все время, в том числе, если для сайта определен «минимальный срок жизни кэша» (который является как минимальным, так и максимальным), или если сайт использует memcache или другую подключаемую систему кэширования, которая использует изменчивые кэши.

Модуль диспетчера обновлений по-прежнему использует таблицу {cache_update}, но вместо использования cache_set(), cache_get()и cache_clear_all()существуют частные вспомогательные функции, которые реализуют те же самые основные задачи, но гарантируют, что кэш не очищен преждевременно, и что данные всегда хранятся в базы данных, даже если используется memcache или другой кеш-сервер.

У менеджера обновлений есть особые потребности, которые необходимы, потому что слишком частая попытка получения информации об обновлении может вызвать проблемы с серверами Drupal.org, учитывая, что диспетчер обновлений может потенциально получать информацию об обновлениях с любого сайта, на котором работает Drupal.

В вашем случае вы можете использовать в [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]качестве идентификатора кеша для одного хранилища кеша. В случае, если вам нужно удалить все записи для объекта, вы можете использовать следующий код.

cache_clear_all("{$module}__{$entity_type}__{$entity_id}__", $bin, TRUE);

Если вы не можете получить значение для назначения $moduleпри очистке кэша или хотите удалить запись кэша независимо от модуля, для которого данные были кэшированы, тогда вы можете использовать другой идентификатор кэша, например [entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from], или [entity_type]__[entity_id]__[module_name]__[string_depending_on_where_the_cache_came_from]. cache_clear_all()удаляет все записи кэша с идентификатором кэша, начиная со строки, переданной в качестве аргумента, когда $wildcardесть TRUE, а идентификатор кэша - нет '*'. В этом случае кэш будет очищен с помощью следующего кода.

cache_clear_all("{$entity_type}__{$entity_id}__", $bin, TRUE);
киамалуно
источник
8

Я не могу придумать вескую причину, по которой удаление записей вручную может вызвать проблемы. Это предполагает, конечно, что вы используете MySQL в качестве бэкэнда для вашего конкретного кэша; хотя я думаю, что то же самое относится к любому другому типу бэкэнда кеша, метод очистки просто не обязательно будет запросом к базе данных.

Если взять в качестве примера модуль обновления ядра, он обходит cache_*функции и очищает свой кеш вручную:

function _update_cache_clear($cid = NULL, $wildcard = FALSE) {
  if (empty($cid)) {
    db_delete('cache_update')
      // Clear everything except fetch task information because these are used
      // to ensure that the fetch task queue items are not added multiple times.
      ->condition('cid', 'fetch_task::%', 'NOT LIKE')
      ->execute();
  }
  else {
    $query = db_delete('cache_update');
    if ($wildcard) {
      $query->condition('cid', $cid . '%', 'LIKE');
    }
    else {
      $query->condition('cid', $cid);
    }
    $query->execute();
  }
}

Я всегда думаю, «если это достаточно хорошо для ядра, это достаточно хорошо для меня» :)

Клайв
источник