Praktik terbaik untuk menerapkan caching khusus?

17

Untuk setiap instance dari setiap jenis entitas, saya menghasilkan sejumlah cache, bernama sesuatu seperti: [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]

Sekarang setiap kali entitas diperbarui, saya ingin menghapus semua cache yang dimulai dengan jenis dan id entitas yang relevan.

Bagaimana saya harus menyimpan / menghapus cache ini?

Saat ini saya hanya cache_set () , tetapi itu menimbulkan masalah ketika saya ingin menghapus, karena saya tidak tahu nama semua cache yang relevan. Apakah aman untuk menghapus entri cache dengan db_delete ()?

Letharion
sumber
Jika Anda tidak tahu nama semua cache yang relevan, bagaimana Anda bisa menggunakannya db_delete()?
kiamlaluno

Jawaban:

6

Untuk menghapus entri dari cache, Anda harus menggunakan cache_clear_all () . Alasannya adalah bahwa implementasi cache yang digunakan tidak bisa menggunakan tabel database dalam database aktif. Itulah yang terjadi dengan kelas DrupalDatabaseCache , tetapi seharusnya tidak benar untuk setiap kelas.

Jika Anda melihat _cache_get_object () (fungsi yang dipanggil oleh cache_get () dan cache_set () ), Anda akan melihat itu berisi kode berikut.

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

Kelas untuk implementasi cache bisa berbeda untuk setiap toko cache cache, dan bahkan yang standar dapat diubah.

Sistem cache status pembaruan pribadi menjelaskan persis mengapa fungsi cache normal tidak digunakan dalam _update_cache_clear () , _update_cache_get () , dan _update_cache_set () . (Penekanan adalah milikku.)

Kami secara khusus TIDAK menggunakan API cache inti untuk menyimpan data yang diambil tentang pembaruan yang tersedia. Sangat penting bahwa cache ini hanya dihapus ketika kita mengisinya setelah berhasil mengambil data pembaruan yang tersedia. Penggunaan API cache inti menghasilkan semua jenis masalah potensial yang akan berakibat pada upaya mengambil data pembaruan yang tersedia setiap saat, termasuk jika situs memiliki "masa cache minimum" (yang merupakan minimum dan maksimum) yang ditentukan, atau jika situs menggunakan memcache atau sistem cache pluggable lain yang mengasumsikan cache volatil.

Modul Update Manager masih menggunakan tabel {cache_update}, tetapi alih-alih menggunakan cache_set(),, cache_get()dan cache_clear_all(), ada fungsi pembantu pribadi yang mengimplementasikan tugas-tugas dasar yang sama ini tetapi memastikan bahwa cache tidak dihapus secara prematur, dan bahwa data selalu disimpan dalam database, bahkan jika memcache atau backend cache lainnya digunakan.

Update Manager memiliki kebutuhan spesifik yang diperlukan karena upaya untuk mengambil informasi pembaruan terlalu sering akan menyebabkan masalah dengan server Drupal.org, mengingat bahwa Update Manager berpotensi mengambil informasi pembaruan dari situs mana pun yang menjalankan Drupal.

Dalam kasus Anda, Anda bisa menggunakan [module_name]__[entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from]sebagai cache ID untuk satu penyimpanan bin cache. Jika Anda perlu menghapus semua entri untuk suatu entitas, Anda bisa menggunakan kode berikut.

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

Jika Anda tidak bisa mendapatkan nilai untuk ditetapkan $moduleketika Anda membersihkan cache, atau Anda ingin menghapus entri cache secara terpisah dari modul yang datanya di-cache, maka Anda dapat menggunakan ID cache yang berbeda, seperti [entity_type]__[entity_id]__[string_depending_on_where_the_cache_came_from], atau [entity_type]__[entity_id]__[module_name]__[string_depending_on_where_the_cache_came_from]. cache_clear_all()menghapus semua entri cache dengan ID cache yang dimulai dengan string berlalu sebagai argumen, saat $wildcardini TRUE, dan ID cache tidak '*'. Dalam hal ini, cache akan dihapus dengan kode berikut.

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

Saya tidak bisa memikirkan alasan bagus mengapa menjatuhkan entri secara manual akan menyebabkan masalah. Tentu saja ini mengasumsikan bahwa Anda menggunakan MySQL sebagai backend untuk cache khusus Anda; Meskipun saya pikir hal yang sama berlaku untuk semua jenis cache backend lainnya, metode untuk menghapus tidak selalu menjadi permintaan basis data.

Jika Anda mengambil modul pembaruan inti sebagai contoh, ia memintas cache_*fungsi dan membersihkan cache secara manual:

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

Saya selalu berpikir "jika itu cukup baik untuk inti, itu cukup baik untuk saya" :)

Clive
sumber