Best Practices für die Implementierung von benutzerdefiniertem Caching?

17

Für jede Instanz jedes Entitätstyps generiere ich eine Reihe von Caches mit dem Namen: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

Jetzt möchte ich bei jeder Aktualisierung einer Entität alle Caches löschen, beginnend mit dem entsprechenden Entitätstyp und der entsprechenden ID.

Wie soll ich diese Caches speichern / löschen?

Momentan habe ich nur cache_set () , aber das ist ein Problem, wenn ich löschen möchte, da ich nicht die Namen aller relevanten Caches kenne. Ist es sicher, Cache-Einträge mit einem db_delete () zu löschen?

Letharion
quelle
Wenn Sie nicht die Namen aller relevanten Caches kennen, wie können Sie sie verwenden db_delete()?
kiamlaluno

Antworten:

6

Um Einträge aus einem Cache zu löschen, sollten Sie cache_clear_all () verwenden . Der Grund dafür ist, dass die verwendete Cache-Implementierung keine Datenbanktabelle in der aktiven Datenbank verwenden konnte. Das ist, was mit der DrupalDatabaseCache- Klasse passiert , aber es sollte nicht für jede Klasse zutreffen.

Wenn Sie sich _cache_get_object () (die von cache_get () und cache_set () aufgerufene Funktion ) ansehen , werden Sie feststellen, dass sie den folgenden Code enthält.

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

Die Klasse für die Cache-Implementierung kann für jeden Cache-Bin-Speicher unterschiedlich sein, und sogar die Standardklasse kann geändert werden.

Das private Update-Status-Cache-System erklärt genau, warum die normalen Cache-Funktionen in _update_cache_clear () , _update_cache_get () und _update_cache_set () nicht verwendet werden . (Der Schwerpunkt liegt bei mir.)

Wir verwenden die Core-Cache-API NICHT speziell zum Speichern der abgerufenen Daten über verfügbare Updates. Es ist von entscheidender Bedeutung, dass dieser Cache nur dann gelöscht wird, wenn er nach dem erfolgreichen Abrufen neuer verfügbarer Aktualisierungsdaten ausgefüllt wird. Die Verwendung der Core-Cache-API führt zu allen möglichen Problemen, die dazu führen würden, dass versucht wird, jederzeit verfügbare Aktualisierungsdaten abzurufen. Dies gilt auch dann, wenn für eine Site eine "minimale Cache-Lebensdauer" (sowohl eine minimale als auch eine maximale) definiert ist. oder wenn eine Site Memcache oder ein anderes steckbares Cachesystem verwendet, das flüchtige Caches voraussetzt.

Das Update Manager - Modul verwendet immer noch den {cache_update} Tisch, aber anstelle der Verwendung cache_set(), cache_get()und cache_clear_all()gibt es Funktionen private Helfer , die die gleichen grundlegenden Aufgaben umzusetzen , aber dafür sorgen , dass der Cache nicht vorzeitig gelöscht, und dass die Daten immer in dem gespeicherten Datenbank, auch wenn Memcache oder ein anderes Cache-Backend verwendet wird.

Der Update Manager hat bestimmte Anforderungen, die erforderlich sind, da der Versuch, Aktualisierungsinformationen zu häufig abzurufen, Probleme mit Drupal.org-Servern verursachen würde, da der Update Manager möglicherweise Aktualisierungsinformationen von jeder Site abrufen kann, auf der Drupal ausgeführt wird.

In Ihrem Fall könnten Sie [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]als Cache-ID für einen einzelnen Cache-Bin-Speicher verwenden. Für den Fall, dass Sie alle Einträge für eine Entität löschen müssen, können Sie den folgenden Code verwenden.

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

Wenn Sie den Wert $modulenicht zum Löschen des Caches zuordnen können oder den Cache-Eintrag unabhängig von dem Modul löschen möchten, für das die Daten zwischengespeichert wurden, können Sie eine andere Cache-ID verwenden, z. B. [entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]oder [entity_type]__[entity_id]__[module_name]__[string_depending_on_where_the_cache_came_from]. cache_clear_all()löscht alle Cache - Einträge mit einem Cache - ID mit der Zeichenfolge beginnen als Argument übergeben, wenn $wildcardist TRUE, und der Cache - ID nicht '*'. In diesem Fall würde der Cache mit dem folgenden Code gelöscht.

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

Ich kann mir keinen guten Grund vorstellen, warum das manuelle Löschen der Einträge ein Problem verursachen würde. Dies setzt natürlich voraus, dass Sie MySQL als Backend für Ihren speziellen Cache verwenden. Obwohl ich denke, dasselbe gilt für jede andere Art von Cache-Backend, wäre die Methode zum Löschen nicht unbedingt eine Datenbankabfrage.

Wenn Sie das Kern-Update-Modul als Beispiel nehmen, werden die cache_*Funktionen umgangen und der Cache wird manuell geleert:

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

Ich denke immer "wenn es gut genug für den Kern ist, ist es gut genug für mich" :)

Clive
quelle