Рекомендации по внедрению пользовательского кэширования?


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

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

Как я должен хранить/очищать эти кэши?

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

 16
Author: acrosman, 2012-07-04

2 answers

Для удаления записей из кэша следует использовать 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);
 6
Author: kiamlaluno, 2012-07-04 21:41:57

Я не могу придумать веской причины, по которой удаление записей вручную могло бы вызвать проблему. Это предполагает, конечно, что вы используете 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();
  }
}

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

 8
Author: Clive, 2012-07-04 16:54:19