file_scan_directory () membutuhkan waktu sekitar 10 detik untuk dieksekusi

10

Menggunakan xhprof saya perhatikan bahwa file_scan_directory()membutuhkan lebih dari 10 detik untuk mengeksekusi ketika halaman depan dimuat. Mengapa harus begitu lama?

Ini adalah output dari xhprofile:

tangkapan layar

hknik
sumber
Anda tidak dapat "file_scan_directory" the "halaman depan", karena halaman depan adalah entri dalam tabel database, bukan jalur sistem file.
Letharion
@Letharion Saya pikir Anda salah mengerti pertanyaan saya. Maksud saya waktu yang dibutuhkan fungsi ini ketika halaman depan dimuat. Saya mengedit pertanyaan.
hknik
Apakah halaman depan benar-benar ada hubungannya dengan fungsi yang mengambil jumlah waktu tertentu? Direktori apa yang sebenarnya Anda pindai? Apa yang ada di direktori?
Letharion
Aha! Saya pikir Anda memanggil fungsi sendiri, dan bertanya-tanya mengapa Anda tidak memberikan rincian lebih lanjut. Jawaban Berdir terlihat sangat masuk akal. :)
Letharion

Jawaban:

14

Sepertinya Anda terpengaruh oleh masalah yang diketahui di Drupal 7 .

Kemungkinan besar, Anda menekan Hindari memindai ulang direktori modul ketika beberapa modul hilang . Itu terjadi jika Anda memiliki beberapa modul yang hilang dalam instalasi Anda. Coba periksa tabel sistem Anda:

SELECT name, filename FROM system WHERE type = 'module' AND status = 1 ORDER BY filename

Dan bersihkan semua modul yang masih diaktifkan tetapi hilang dari sistem file.

Secara keseluruhan, Drupal 7 jauh lebih ramah sumber daya dan skalabel dibandingkan Drupal 6, selain beberapa regresi yang kurang menguntungkan seperti ini.

Melihat fungsi-fungsi itu, sepertinya tidak ada modul atau mungkin satu file modul. Lihatlah drupal_get_filename () , ia memanggil drupal_system_listing (), yang memanggil fungsi ini jika tidak dapat menemukan file yang diminta. Tambahkan dpm (func_get_args ()) tepat sebelum memanggil drupal_system_listing (), yang akan memberi tahu Anda file mana yang tidak ditemukannya.

Berdir
sumber
Tidak. Sayangnya (!) Tidak ada modul yang hilang dari sistem file
hknik
Maka Anda perlu melacak dari mana panggilan itu berasal, mungkin modul kustom atau contrib melakukan kesalahan. Klik fungsi induk dari file_scan_directory () dan perbarui posting awal dengan daftar fungsi induk.
Berdir
Melihat fungsi-fungsi itu, sepertinya tidak ada modul atau mungkin satu file modul. Lihatlah drupal_get_filename: api.drupal.org/api/drupal/includes!bootstrap.inc/function/… . Itu memanggil fungsi jika tidak dapat menemukan file yang diminta. Tambahkan dpm (func_get_args ()) tepat sebelum memanggil drupal_system_listing (), yang akan memberi tahu Anda fungsi mana yang tidak ditemukannya.
Berdir
@Berdir Komentar terakhir Anda harus dalam jawaban Anda, karena relevan.
kiamlaluno
Tautan ke "masalah yang diketahui di Drupal 7" dan "Hindari direktori modul rescanning" terputus. Keduanya adalah mantan jawaban stackexchange. Adakah yang punya referensi lain?
rfay
4

Ada beberapa alasan mengapa masalah ini muncul, dan saya sangat cemas, sekarang saya merasa agak berpengetahuan tentang alasan-alasan itu. Frustasi, jika Anda baru saja melihat masalah ini setelah memutakhirkan Drupal core ke 7.33+, ini bisa menjadi kesalahan ketik pada modul apa pun, bahkan jika Anda belum memutakhirkan modul itu.

Modul dihapus dari basis kode

Anda mungkin ingin memeriksa bug yang dikenal oleh @Berdir, terutama jika Anda baru saja menghapus modul "tidak terpakai" dari basis kode. Untuk mengetahui apakah Anda memiliki modul yang diaktifkan tetapi telah dihapus dari sistem file, Anda dapat menjalankan skrip seperti yang disebutkan di sini - atau menggunakan milik saya, ditulis untuk instalasi multi-situs pada sistem dengan drush, untuk dijalankan dari direktori basis Drupal:

find sites -maxdepth 1 -iname '*.*' -type d | sed -rne 's:sites/(.+):echo \1; drush @\1 sqlq "select filename from system where status = 1" | grep "/" | sed -rne "s_(.+)_test -f \\1 || echo \\1_p" | bash:p' | bash

atau yang berikut ini:

while read -r file; do [ -f "$file" ] || echo "$file is missing."; done < <(drush sqlq "SELECT filename FROM system WHERE status = 1")

Jika Anda menemukan modul yang telah dihapus dari basis kode, ikuti petunjuk dalam masalah yang disebutkan oleh @Berdir.

Kesalahan pengkodean

Jika bukan itu, situasi Anda kemungkinan disebabkan oleh kesalahan pengkodean, seperti file yang telah dihapus tetapi masih ditambahkan oleh panggilan drupal_add_js (dari komentar 19 dalam edisi # 1082892) atau salah ketik yang salah dalam modul atau tema , mis. imagecache_actions(lihat https://drupal.org/node/2381357 ).

Bagaimanapun, untuk mencari tahu persis mengapa ini terjadi, Anda perlu tahu persis file mana yang tidak ditemukan oleh Drupal. Jadi, sesuai komentar Berdir, Anda dapat sementara hack drupal_get_filenamedi bootstrap.incdengan menambahkan log atau pesan panggilan sebelum panggilan untuk drupal_system_listing(). Jika Anda memiliki modul Devel diinstal maka dpmakan berfungsi; jika tidak, Anda bisa menggunakan drupal_set_messageatau syslog. Contoh:

dpm(func_get_args());
drupal_set_message(implode(', ', func_get_args()));
syslog(LOG_WARNING, implode(', ', func_get_args()));

Setelah Anda tahu apa yang dicari Drupal, itu adalah taruhan yang bagus bahwa Anda akan dapat mengetahui ke mana harus pergi dari sana. Masalah saya disebabkan oleh panggilan untuk memasukkan file dari modul yang tidak ada imagcache_actions(perhatikan salah ketik). Jadi, saya mencari imagecache_actionsdi basis kode saya (misalnya grep -r imagcache_actions .), dan menemukan bahwa versi 1.4 imagecache_canvasactions.modulemenggunakan module_load_include di luar semua panggilan fungsi, dalam lingkup file, dengan kesalahan ketik. Sekali lagi, kesalahan ini hanya terekspos setelah memperbarui ke Drupal 7.33+. Saya menemukan bahwa masalah telah dibuat untuk imagecache_actions, menerapkan tambalan, dan kembali berbisnis.

David Hunt
sumber
2

Saya memiliki masalah yang sangat mirip - file_scan_directory()membunuh situs. Ternyata node_modulesfolder huuge yang tertanam di dalam tema khusus saya gulpsedang dipindai setiap flush cache. Memindahkan file-file ini dari folder tema (dan memperbarui beberapa jalur di gulpfile saya) sepertinya memperbaikinya untuk saya. Atau: Saya pikir Anda bisa meretas file.inc:

'nomask' => '/(\.\.?|CVS|node_modules)$/', // https://www.drupal.org/node/2329453#comment-9360519

williamsowen
sumber
0

Ini file_scan_directory()adalah fungsi rekursif yang semua file cocok dengan direktori yang diberikan. Penggunaan is_dir()dan opendir()panggilan PHP yang mungkin paling mahal dalam hal panggilan sistem I / O. Bootstrap Drupal sederhana (mis. time drush ev "") Dapat memanggil file_scan_directorybeberapa ribu kali (tergantung pada kompleksitas hierarki folder Drupal Anda, mis. Jumlah modul dan foldernya).

Dalam kasus saya, saya memiliki ~ 1500 panggilan ke file_scan_directory(total 24 detik terdiri dari 2 panggilan dari drupal_system_listingdalam common.inc, kemudian panggilan lain dibagi dengan panggilan rekursif ke file_scan_directorydirinya sendiri.

Untuk meningkatkan kinerja panggilan I / O, Anda perlu menerapkan caching file. Ini dapat dicapai dengan menginstal dan mengaktifkan OPCache ( opcache.enable=1) dan mengubah pengaturannya (lihat: Cara menggunakan PHP OPCache? ). Menggunakan caching berbasis memori seperti memcached / redis juga disarankan.

Saat menggunakan antarmuka baris perintah (seperti drush), Anda juga harus mengaktifkan opcache.enable_cli=1.

Setelah perubahan, Anda dapat memeriksa syscalls yang lebih banyak menggunakan beberapa debugger yang tersedia.

Misalnya

  • Di Linux menggunakan strace(tekan Ctrl- Cuntuk menyelesaikan):

    sudo strace -c -fp $(pgrep -n php)
  • On Unix using dtrace(menggunakan probe statis DTrace PHP ), mis

    sudo dtrace -n 'inline string NAME = "php"; syscall:::entry /(NAME == strstr(NAME, execname)) || (execname == strstr(execname, NAME))/ { @num[probefunc] = count(); }'

Anda selanjutnya dapat mempertimbangkan untuk mengoptimalkan drupal_system_listing()atau file_scan_directory()dengan menerapkan cache statis, misalnya

--- a/includes/file.inc
+++ b/includes/file.inc
@@ -2104,6 +2104,8 @@ function file_download_access($uri) {
  *   'filename', and 'name' members corresponding to the matching files.
  */
 function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
+  static $dirs = array();
+
   // Merge in defaults.
   $options += array(
     'nomask' => '/(\.\.?|CVS)$/',
@@ -2120,7 +2122,12 @@ function file_scan_directory($dir, $mask, $options = array(), $depth = 0) {
       if (!preg_match($options['nomask'], $filename) && $filename[0] != '.') {
         $uri = "$dir/$filename";
         $uri = file_stream_wrapper_uri_normalize($uri);
-        if (is_dir($uri) && $options['recurse']) {
+
+        if (empty($dirs[$uri])) {
+          $dirs[$uri] = is_dir($uri);
+        }
+
+        if ($dirs[$uri] && $options['recurse']) {
           // Give priority to files in this folder by merging them in after any subdirectory files.
           $files = array_merge(file_scan_directory($uri, $mask, $options, $depth + 1), $files);

Atau untuk caching file_scan_directorypanggilan dari drupal_system_listing(), kemudian periksa tambalan berikut tersedia di: file_scan_directory harus di-cache .

kenorb
sumber