file_scan_directory () dosyasının yürütülmesi yaklaşık 10 saniye sürer


10

Xhprof kullanma file_scan_directory()Ön sayfa yüklendiğinde yürütülmesi 10 saniyeden uzun sürdü. Neden bu kadar uzun sürmeli?

Bu xhprofile çıktısıdır:

ekran görüntüsü


Ön sayfa, bir dosya sistemi yolu değil, bir veritabanı tablosundaki bir girdi olduğundan "file_scan_directory" "ön sayfa" olamaz.
Letharion

@Letharion Sanırım sorumu yanlış anladın. Yani bu fonksiyonun ön sayfa yüklendiğinde geçeceği zaman.
hknik

Ön sayfanın gerçekten belirli bir zaman alan işlevle ilgisi var mı? Gerçekten hangi dizini tarıyorsunuz? Dizinde ne var?
Letharion

Aha! İşlevi kendiniz aradığınızı düşündüm ve neden daha fazla ayrıntı sağlamadığınızı merak ettim. Berdir'in cevabı çok makul görünüyor. :)
Letharion

Yanıtlar:


14

Drupal 7'de bilinen bir sorundan etkilendiğiniz anlaşılıyor .

Büyük olasılıkla, birden fazla modül eksik olduğunda modül dizinini yeniden taramaktan kaçının . Kurulumunuzda bazı eksik modüller varsa olur. Sistem tablonuzu kontrol etmeye çalışın:

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

Ve hala etkin olan ancak dosya sisteminden eksik olan tüm modülleri temizleyin.

Genel olarak, Drupal 7, bu gibi talihsiz regresyonlar dışında, Drupal 6'dan çok daha kaynak dostu ve ölçeklendirilebilir.

Bu işlevlere baktığımızda, bir modül veya bir modülün tek bir dosyası eksik gibi görünüyor. Drupal_get_filename () ' a bir göz atın , istenen dosyayı bulamazsa bu işlevi çağıran drupal_system_listing () öğesini çağırır. Drupal_system_listing () öğesini çağırmadan hemen önce bir dpm (func_get_args ()) ekleyin, bu size hangi dosyayı bulamadığını söylemelidir.


Hayır. Ne yazık ki (!) Dosya sisteminden hiçbir modül eksik
hknik

Daha sonra, çağrının geldiği yerden izlemeniz gerekir, belki özel veya katkıda bulunan bir modül yanlış bir şey yapıyor. File_scan_directory () öğesinin üst işlevlerine tıklayın ve ilk yayını üst işlevler listesiyle güncelleyin.
Berdir

Bu fonksiyonların bakıldığında gelmez bir modül ya da belki bir modül tek bir dosya eksik gibi görünüyor. Drupal_get_filename sitesine bir göz atın: api.drupal.org/api/drupal/includes!bootstrap.inc/function/… . İstenen dosyayı bulamazsa işlevi çağırır. Drupal_system_listing () öğesini çağırmadan hemen önce bir dpm (func_get_args ()) ekleyin, bu size hangi işlevi bulamadığını söylemelidir.
Berdir

@Berdir Son yorumunuz alakalı olduğu gibi cevabınızda olmalıdır.
kiamlaluno

"Drupal 7'de bilinen sorun" ve "Modül dizinini yeniden taramaktan kaçının" bağlantıları koptu. Her ikisi de eski stackexchange cevaplarıdır. Başka referansı olan var mı?
rfay

4

Bu sorunun ortaya çıkmasının birkaç nedeni var ve büyük dehşet içinde, şimdi kendimi bu nedenler hakkında biraz bilgili buluyorum. Sinir bozucu bir şekilde, Drupal çekirdeğini 7.33+ sürümüne yükselttikten sonra bu sorunu fark ettiyseniz, bu modülü yükseltmemiş olsanız bile, bu herhangi bir modülde bir yazım hatası olabilir.

Kod tabanından kaldırılan modüller

İlk olarak @Berdir'in bahsettiği bilinen hatayı kontrol etmek isteyebilirsiniz, özellikle de "kullanılmayan" modülleri kod tabanından kaldırıyorsanız. Etkinleştirilmiş ancak dosya sisteminden kaldırılmış modülleriniz olup olmadığını öğrenmek için, burada belirtilen gibi bir komut dosyası çalıştırabilir veya çalışacak bir sisteme çok siteli kurulum için yazılmış mayın kullanabilirsiniz. Drupal temel dizininden:

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

veya aşağıdakiler:

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

Kod tabanından kaldırılmış bir modül bulursanız, @Berdir'in belirttiği sorunlardaki talimatları izleyin.

Kodlama hataları

Durum böyle değilse, durumunuza büyük olasılıkla kaldırılmış ancak hala bir drupal_add_js çağrısı (# 1082892 sayıdaki 19 numaralı yorumdan itibaren) veya bir modül veya temadaki talihsiz bir yazım hatası gibi bir kodlama hatası neden olmaktadır. , örneğin imagecache_actions(bkz. https://drupal.org/node/2381357 ).

Her durumda, bunun neden olduğunu tam olarak anlamak için, Drupal'ın hangi dosyayı bulamadığını tam olarak bilmeniz gerekir. Yani, Berdir yorumuna göre, geçici olarak kesmek olabilir drupal_get_filenamede bootstrap.inchemen çağrısı önce bir günlük veya mesaj çağrısı ekleyerek drupal_system_listing(). Devel modülünüz kurulu dpmise çalışır; değilse, drupal_set_messageveya syslog kullanabilirsiniz . Örnekler:

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

Drupal'ın ne aradığını öğrendikten sonra, oradan nereye gideceğinizi anlayabileceğiniz iyi bir bahis. Benim sorunum olmayan modülden bir dosya eklemek için bir çağrı neden oldu imagcache_actions(yazım hatası not edin). Bu nedenle, imagecache_actionskod tabanımda (örneğin grep -r imagcache_actions .) aradım ve 1.4 sürümü imagecache_canvasactions.modulemodülünün herhangi bir işlev çağrısının dışında, dosya kapsamında, bir yazım hatasıyla kullandığını buldum. Yine, bu hata sadece Drupal 7.33+ sürümüne güncellendikten sonra ortaya çıktı. Zaten için bir sorun oluşturulduğunu imagecache_actions, yamayı uyguladığını ve işe geri döndüğünü buldum .


2

Çok benzer bir sorunum vardı - file_scan_directory()siteyi öldürüyordum. Her önbellek sifonu tarandığı node_modulesiçin özel temam içine gömülmüş bir huuge klasörü çıkıyor gulp. Bu dosyaları tema klasöründen çıkarmak (ve gulpfile'mdaki bazı yolları güncellemek) benim için düzeltmiş gibi görünüyordu. Alternatif olarak: Bence hack yapabilirsiniz file.inc:

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


0

file_scan_directory()Tüm dosyalar, belirli bir dizin için eşleşen bir özyinelemeli fonksiyonudur. I / O sistem çağrıları açısından en pahalı olabilen kullanımları is_dir()ve opendir()PHP çağrıları. Basit Drupal önyükleme (örn. time drush ev "") file_scan_directoryBirkaç bin defadan fazla çağrı yapabilir (Drupal klasör hiyerarşinizin karmaşıklığına bağlı olarak, örneğin modül sayısı ve klasörleri).

Benim durumumda ben ~ 1500 çağrıları vardı file_scan_directorytoplam oluşan 2 çağrılarında 24 saniye ( drupal_system_listingiçinde common.incdaha sonra diğer aramalar için özyinelemeli çağrılar tarafından bölünmüş olduğunu, file_scan_directoryit-öz.

G / Ç çağrılarındaki performansı artırmak için dosya önbelleğe almayı uygulamanız gerekir. Bu, OPCache ( opcache.enable=1) kurup etkinleştirerek ve ayarlarını değiştirerek elde edilebilir (bkz: PHP OPCache nasıl kullanılır? ). Memcached / redis gibi bellek tabanlı önbellek kullanımı da önerilir.

Komut satırı arabirimini (örneğin drush) kullanırken de etkinleştirmeniz gerekir opcache.enable_cli=1.

Değişiklikten sonra, mevcut bazı hata ayıklayıcıları kullanarak daha fazla tüketilen sistem çağrılarını kontrol edebilirsiniz.

Örneğin

  • Linux'ta strace( bitirmek için vur Ctrl- C):

    sudo strace -c -fp $(pgrep -n php)
  • Unix kullanarak dtrace( PHP'nin DTrace statik problarını kullanarak ), ör.

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

Ayrıca optimize etmeyi drupal_system_listing()veya file_scan_directory()statik önbellek uygulayarak, ör.

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

Veya, file_scan_directorygelen aramaları önbelleğe almak için drupal_system_listing(), şu adreste bulunan şu yamayı kontrol edin: file_scan_directory önbelleğe alınmalıdır .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.