Meilleures pratiques pour implémenter la mise en cache personnalisée?


17

Pour chaque instance de chaque type d'entité, je génère un certain nombre de caches, nommés quelque chose comme: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

Maintenant, chaque fois qu'une entité est mise à jour, je souhaite supprimer tous les caches en commençant par le type d'entité et l'ID appropriés.

Comment dois-je stocker / effacer ces caches?

Actuellement, je viens de cache_set () , mais cela pose un problème lorsque je veux effacer, car je ne connais pas les noms de tous les caches pertinents. Est-il sûr de supprimer des entrées de cache avec un db_delete ()?


Si vous ne connaissez pas les noms de tous les caches pertinents, comment pouvez-vous les utiliser db_delete()?
kiamlaluno

Réponses:


6

Pour supprimer des entrées d'un cache, vous devez utiliser cache_clear_all () . La raison en est que l'implémentation du cache utilisé n'a pas pu utiliser une table de base de données dans la base de données active. C'est ce qui se produit avec la classe DrupalDatabaseCache , mais cela ne devrait pas être vrai pour toutes les classes.

Si vous regardez _cache_get_object () (la fonction appelée par cache_get () et cache_set () ), vous remarquerez qu'il contient le code suivant.

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

La classe pour l'implémentation du cache peut être différente pour chaque magasin de cache, et même celle par défaut peut être modifiée.

Le système de cache d'état de mise à jour privée explique exactement pourquoi les fonctions de cache normales ne sont pas utilisées dans _update_cache_clear () , _update_cache_get () et _update_cache_set () . (L'accent est sur moi.)

Nous n'utilisons PAS spécifiquement l'API de cache principale pour enregistrer les données extraites sur les mises à jour disponibles. Il est extrêmement important que ce cache ne soit effacé que lorsque nous le remplissons après avoir récupéré avec succès les nouvelles données de mise à jour disponibles. L'utilisation de l'API du cache principal entraîne toutes sortes de problèmes potentiels qui entraîneraient une tentative de récupération permanente des données de mise à jour disponibles, y compris si un site a une "durée de vie du cache minimale" (qui est à la fois un minimum et un maximum) définie, ou si un site utilise memcache ou un autre système de cache enfichable qui suppose des caches volatils.

Le module Update Manager utilise toujours le {cache_update} table, mais au lieu d'utiliser cache_set(), cache_get()et cache_clear_all(), il y a des fonctions d'aide privées qui mettent en œuvre ces mêmes tâches de base , mais veiller à ce que le cache ne soit pas effacé prématurément, et que les données sont toujours stockées dans la base de données, même si memcache ou un autre backend de cache est utilisé.

Le gestionnaire de mise à jour a des besoins spécifiques qui sont nécessaires car tenter de récupérer les informations de mise à jour trop fréquemment entraînerait des problèmes avec les serveurs Drupal.org, étant donné que le gestionnaire de mise à jour peut potentiellement récupérer les informations de mise à jour à partir de n'importe quel site exécutant Drupal.

Dans votre cas, vous pouvez utiliser [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]comme ID de cache pour un seul magasin de bacs de cache. Dans le cas où vous devez supprimer toutes les entrées d'une entité, vous pouvez utiliser le code suivant.

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

Si vous ne pouvez pas obtenir la valeur à affecter $modulelorsque vous videz le cache ou si vous souhaitez supprimer l'entrée de cache indépendamment du module pour lequel les données ont été mises en cache, vous pouvez utiliser un ID de cache différent, tel que [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()supprime toutes les entrées de cache avec un ID de cache commençant par la chaîne passée en argument, quand $wildcardest TRUE, et l'ID de cache ne l'est pas '*'. Dans ce cas, le cache serait effacé avec le code suivant.

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

8

Je ne peux pas penser à une bonne raison pour laquelle la suppression manuelle des entrées entraînerait un problème. Cela suppose, bien sûr, que vous utilisez MySQL comme backend pour votre cache particulier; bien que je pense que la même chose s'applique à tout autre type de backend de cache, la méthode pour effacer ne serait pas nécessairement une requête de base de données.

Si vous prenez le module de mise à jour principal comme exemple, il contourne les cache_*fonctions et vide son cache manuellement:

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

Je pense toujours "si c'est assez bon pour le noyau, c'est assez bon pour moi" :)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.