Práticas recomendadas para implementar o cache personalizado?

17

Para todas as instâncias de todo tipo de entidade, eu gero vários caches, chamados algo como: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

Agora, sempre que uma entidade é atualizada, desejo descartar todos os caches começando com o tipo e o ID da entidade relevante.

Como devo armazenar / limpar esses caches?

Atualmente, apenas cache_set () , mas isso apresenta um problema quando quero limpar, pois não sei os nomes de todos os caches relevantes. É seguro descartar entradas de cache com um db_delete ()?

Letharion
fonte
Se você não souber os nomes de todos os caches relevantes, como você pode usá-lo db_delete()?
kiamlaluno

Respostas:

6

Para excluir entradas de um cache, você deve usar cache_clear_all () . O motivo é que a implementação de cache usada não pôde usar uma tabela de banco de dados no banco de dados ativo. É o que acontece com a classe DrupalDatabaseCache , mas não deve ser verdadeira para todas as classes.

Se você olhar para _cache_get_object () (a função chamada cache_get () e cache_set () ), você notará que ele contém o seguinte código.

  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];

A classe para a implementação do cache pode ser diferente para cada armazenamento na lixeira, e mesmo o padrão pode ser alterado.

O sistema de cache de status de atualização particular explica exatamente por que as funções normais de cache não são usadas em _update_cache_clear () , _update_cache_get () e _update_cache_set () . (A ênfase é minha.)

NÃO usamos especificamente a API do cache principal para salvar os dados buscados sobre as atualizações disponíveis. É de vital importância que esse cache seja limpo apenas quando o preenchermos após a busca com êxito de novos dados de atualização disponíveis. O uso da API do cache principal resulta em todos os tipos de problemas em potencial que resultariam na tentativa de buscar dados de atualização disponíveis o tempo todo, inclusive se um site tiver uma "vida útil mínima do cache" (que seja mínima e máxima) definida, ou se um site usa memcache ou outro sistema de cache conectável que assume caches voláteis.

O módulo Update Manager ainda usa a {cache_update} mesa, mas em vez de usar cache_set(), cache_get()e cache_clear_all(), há funções auxiliares privadas que implementam essas mesmas tarefas básicas, mas garantir que o cache não for prematuramente eliminado, e que os dados são sempre armazenados na banco de dados, mesmo se o memcache ou outro back-end do cache estiver em uso.

O Update Manager tem necessidades específicas necessárias, porque tentar obter informações de atualização com muita freqüência causaria problemas nos servidores Drupal.org, considerando que o Update Manager pode buscar informações de atualização em qualquer site que esteja executando o Drupal.

No seu caso, você pode usar [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]como ID de cache para um único armazenamento de bin de cache. No caso de você precisar excluir todas as entradas de uma entidade, você pode usar o seguinte código.

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

Se você não conseguir obter o valor a ser atribuído ao $modulelimpar o cache ou desejar excluir a entrada do cache independentemente do módulo para o qual os dados foram armazenados em cache, poderá usar um ID de cache diferente, como [entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from], ou [entity_type]__[entity_id]__[module_name]__[string_depending_on_where_the_cache_came_from]. cache_clear_all()exclui todas as entradas de cache com um ID de cache começando com a cadeia passada como argumento, quando $wildcardfor TRUE, e o ID de cache não '*'. Nesse caso, o cache seria limpo com o seguinte código.

cache_clear_all("{$entity_type}__{$entity_id}__", $bin, TRUE);
kiamlaluno
fonte
8

Não consigo pensar em uma boa razão pela qual a exclusão manual das entradas causaria um problema. Isso pressupõe, é claro, que você esteja usando o MySQL como back-end para seu cache específico; Embora eu ache que o mesmo se aplica a qualquer outro tipo de back-end de cache, o método para limpar não seria necessariamente uma consulta ao banco de dados.

Se você usar o módulo de atualização principal como exemplo, ele ignora as cache_*funções e limpa seu cache manualmente:

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();
  }
}

Eu sempre penso "se é bom o suficiente para o núcleo, é bom o suficiente para mim" :)

Clive
fonte