Рекомендации по внедрению пользовательского кэширования?
Для каждого экземпляра сущности каждого типа я создаю несколько кэшей, названных примерно так: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]
Теперь всякий раз, когда объект обновляется, я хочу удалять все кэши, начиная с соответствующего типа и идентификатора объекта.
Как я должен хранить/очищать эти кэши?
В настоящее время я просто cache_set(), но это создает проблему, когда я хочу очистить, так как я не знаю имен всех соответствующих кэшей. Безопасно ли удалять записи кэша с помощью db_delete()?
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);
Я не могу придумать веской причины, по которой удаление записей вручную могло бы вызвать проблему. Это предполагает, конечно, что вы используете 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, это достаточно хорошо для меня":)