¿Mejores prácticas para implementar el almacenamiento en caché personalizado?

17

Para cada instancia de cada tipo de entidad, genero un número de cachés, llamado algo así como: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

Ahora, cada vez que se actualiza una entidad, quiero eliminar todas las cachés comenzando con el tipo de entidad relevante y la identificación.

¿Cómo debo almacenar / borrar estos cachés?

Actualmente solo uso cache_set () , pero eso presenta un problema cuando quiero borrar, ya que no sé los nombres de todos los cachés relevantes. ¿Es seguro soltar las entradas de caché con un db_delete ()?

Letharion
fuente
Si no conoce los nombres de todos los cachés relevantes, ¿cómo puede usarlos db_delete()?
kiamlaluno

Respuestas:

6

Para eliminar entradas de un caché, debe usar cache_clear_all () . La razón es que la implementación de caché utilizada no pudo utilizar una tabla de base de datos en la base de datos activa. Eso es lo que sucede con la clase DrupalDatabaseCache , pero no debería ser cierto para todas las clases.

Si observa _cache_get_object () (la función llamada por cache_get () y cache_set () ), notará que contiene el siguiente 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];

La clase para la implementación de la caché podría ser diferente para cada almacén de caché e incluso se podría cambiar la predeterminada.

El sistema de caché de estado de actualización privada explica exactamente por qué las funciones normales de caché no se usan en _update_cache_clear () , _update_cache_get () y _update_cache_set () . (El énfasis es mío).

Específicamente, NO utilizamos la API de caché central para guardar los datos recuperados sobre las actualizaciones disponibles. Es de vital importancia que este caché solo se borre cuando lo rellenemos después de recuperar con éxito los nuevos datos de actualización disponibles. El uso de la API de caché central da como resultado todo tipo de problemas potenciales que resultarían en intentar obtener los datos de actualización disponibles todo el tiempo, incluso si un sitio tiene una "vida útil de caché mínima" (que es tanto mínima como máxima) definida, o si un sitio usa memcache u otro sistema de caché conectable que asume cachés volátiles.

El módulo Update Manager todavía usa la tabla {cache_update}, pero en lugar de usar cache_set(), cache_get()y cache_clear_all(), hay funciones auxiliares privadas que implementan estas mismas tareas básicas pero aseguran que el caché no se borre prematuramente y que los datos siempre se almacenen en el base de datos, incluso si Memcache u otro backend de caché está en uso.

El Administrador de actualizaciones tiene necesidades específicas que son necesarias porque intentar obtener información de actualización con demasiada frecuencia causaría problemas con los servidores de Drupal.org, teniendo en cuenta que el Administrador de actualizaciones puede obtener información de actualización de cualquier sitio que ejecute Drupal.

En su caso, puede usarlo [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]como ID de caché para un único almacén bin de caché. En el caso de que necesite eliminar todas las entradas de una entidad, puede usar el siguiente código.

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

Si no puede obtener el valor para asignar $modulecuando está borrando la memoria caché, o si desea eliminar la entrada de la memoria caché independientemente del módulo para el que se han almacenado los datos en caché, puede usar una ID de memoria caché diferente, como [entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from], o [entity_type]__[entity_id]__[module_name]__[string_depending_on_where_the_cache_came_from]. cache_clear_all()elimina todas las entradas de caché con una ID de caché que comienza con la cadena pasada como argumento, cuando $wildcardes TRUE, y la ID de caché no lo es '*'. En este caso, el caché se borrará con el siguiente código.

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

No puedo pensar en una buena razón por la cual soltar las entradas manualmente podría causar un problema. Esto supone, por supuesto, que está utilizando MySQL como back-end para su caché particular; Aunque creo que lo mismo se aplica a cualquier otro tipo de backend de caché, el método para borrar simplemente no sería necesariamente una consulta de base de datos.

Si toma el módulo de actualización central como ejemplo, omite las cache_*funciones y borra su caché 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();
  }
}

Siempre pienso "si es lo suficientemente bueno para el núcleo, es lo suficientemente bueno para mí" :)

Clive
fuente