file_scan_directory()の実行には約10秒かかります


10

xhprofを使用file_scan_directory()すると、フロントページのロード時に実行に10秒以上かかることに気付きました。なぜそんなに時間がかかるのでしょうか?

これはxhprofileの出力です:

スクリーンショット


フロントページはファイルシステムパスではなくデータベーステーブルのエントリであるため、「フロントページ」を「file_scan_directory」することはできません。
Letharion 2012年

@レサリオン私はあなたが私の質問を誤解していると思います。フロントページが読み込まれるときにこの関数にかかる時間を意味します。質問を編集しました。
hknik 2012年

フロントページは本当に特定の時間をとる機能と関係がありますか?実際にスキャンしているディレクトリは何ですか?ディレクトリには何がありますか?
Letharion 2012年

ああ!自分で関数を呼び出したと思いましたが、なぜ詳細を提供しなかったのかと思いました。Berdirの答えは非常に合理的に見えます。:)
Letharion

回答:


14

Drupal 7の既知の問題の影響を受けているようです。

おそらく、複数のモジュールが見つからない場合は、モジュールディレクトリの再スキャン避けてください。これは、インストールに不足しているモジュールがある場合に発生します。システムテーブルを確認してください。

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

まだ有効になっているがファイルシステムにないモジュールをクリーンアップします。

全体として、Drupal 7は、Drupal 6よりもリソースに優しく、スケーラブルです。

これらの関数を見ると、モジュールまたはモジュールの単一のファイルが欠落しているように見えます。drupal_get_filename()を見てください。drupal_system_listing()が呼び出され、要求されたファイルが見つからない場合にこの関数が呼び出されます。drpal_system_listing()を呼び出す直前にdpm(func_get_args())を追加すると、どのファイルが見つからないかがわかります。


いいえ。残念ながら(!)ファイルシステムにモジュールがありません
hknik

次に、呼び出しがどこから来ているかをトレースする必要があります。カスタムモジュールまたはcontribモジュールが何か問題を起こしている可能性があります。file_scan_directory()の親関数をクリックし、親関数のリストを使用して最初の投稿を更新します。
Berdir

これらの関数を見ると、モジュールまたはモジュールの単一のファイルが欠落ているように見えます。drupal_get_filename:api.drupal.org/api/drupal/includes!bootstrap.inc/function/…をご覧ください。要求されたファイルが見つからない場合は、関数を呼び出します。drpal_system_listing()を呼び出す直前にdpm(func_get_args())を追加します。これにより、見つからない関数がわかります。
Berdir

@Berdir最後のコメントは関連があるので、回答に含める必要があります。
kiamlaluno

「Drupal 7の既知の問題」および「モジュールディレクトリの再スキャンを回避する」へのリンクが壊れています。どちらも以前のstackexchangeの回答です。誰か他の参照がありますか?
rfay 2015

4

この問題が発生する理由はいくつかありますが、非常に残念なことに、私はそれらの理由についてある程度知っています。イライラして、Drupalコアを7.33+にアップグレードした後にこの問題に気付いた場合、そのモジュールをアップグレードしていなくても、これは任意のモジュールのタイプミスである可能性があります。

コードベースから削除されたモジュール

@Berdirが言及している既知のバグを最初に確認することをお勧めします。特に、最近「未使用」のモジュールをコードベースから削除している場合はなおさらです。有効になっているがファイルシステムから削除されているモジュールがあるかどうかを確認するには、ここに記載されているようなスクリプトを実行するか、drushを使用してシステムにマルチサイトインストール用に作成された鉱山を使用して実行します。 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

または以下:

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

コードベースから削除されたモジュールを見つけた場合は、@ Berdirが言及した問題の指示に従ってください。

コーディングエラー

そうでない場合は、削除されたがdrupal_add_js呼び出し(問題#1082892のコメント19から)またはモジュールまたはテーマの不幸な誤植によってまだ追加されているファイルなど、コーディングエラーが原因である可能性があります。例imagecache_actionshttps://drupal.org/node/2381357を参照)。

いずれにせよ、これが発生している理由を正確に把握するには、Drupalが検出できないファイルを正確に知る必要があります。だから、Berdirさんのコメントどおり、あなたは一時的にハックすることができdrupal_get_filenamebootstrap.incだけを呼び出す前に、ログやメッセージの呼び出しを追加することによってdrupal_system_listing()。Develモジュールがインストールされている場合dpmは機能します。そうでない場合は、drupal_set_messageまたはsyslog を使用できます。例:

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

Drupalが何を探しているのかがわかったら、そこからどこに行くべきかを理解できるようになるでしょう。私の問題は、存在しないモジュールからのファイルを含めるための呼び出しが原因でしたimagcache_actions(タイプミスに注意してください)。したがって、imagecache_actionsコードベース(例:)で検索したgrep -r imagcache_actions .ところ、バージョン1.4 imagecache_canvasactions.moduleは、関数呼び出しの外で、ファイルスコープ内にタイプミスがあるmodule_load_include を使用していることがわかりました。繰り返しますが、このエラーはDrupal 7.33以降にアップデートした後にのみ公開されました。の問題が既に作成されておりimagecache_actions、パッチを適用しており、ビジネスに復帰していることがわかりました。


2

私は非常に類似した問題を抱えていました- file_scan_directory()サイトを殺していました。node_modulesカスタムテーマに埋め込まれた巨大なフォルダーgulpが、キャッシュフラッシュごとにスキャンされていたことがわかりました。これらのファイルをテーマフォルダーから移動して(そしてgulpfileのいくつかのパスを更新して)、それを修正したようです。あるいは、ハッキングできると思いますfile.inc

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


0

file_scan_directory()すべてのファイル指定されたディレクトリのために一致して再帰関数です。これはis_dir()opendir()I / Oシステムコールの観点から最も時間がかかる可能性があるPHPコールを使用します。単純なDrupalブートストラップ(例:)time drush ev ""file_scan_directory、数千回を超える場合があります(Drupalフォルダー階層の複雑さ(モジュールとそのフォルダーの数など)によって異なります)。

私の場合は、へ〜1500回の呼び出しだったfile_scan_directoryから、2つの呼び出しからなる合計で(24秒drupal_system_listingではcommon.inc、他のコールがに再帰呼び出しによって分割された、file_scan_directoryそれは自己。

I / O呼び出しのパフォーマンスを向上させるには、ファイルキャッシュを実装する必要があります。これは、OPCache(opcache.enable=1)をインストールして有効にし、その設定を調整することで実現できます(「PHP OPCacheの使用方法」を参照)。memcached / redisなどのメモリベースのキャッシュを使用することもお勧めします。

コマンドラインインターフェイス(などdrush)を使用する場合は、も有効にする必要がありますopcache.enable_cli=1

変更後、利用可能なデバッガーを使用して、より多くのシステムコールをチェックできます。

例えば

  • Linuxの場合strace(ヒットCtrl- C終了):

    sudo strace -c -fp $(pgrep -n php)
  • UnixではdtracePHPのDTrace静的プローブを使用して)、たとえば

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

あなたはさらに最適化を検討するdrupal_system_listing()file_scan_directory()、静的キャッシュを実装することで、例えば

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

または、file_scan_directoryからの呼び出しをキャッシュdrupal_system_listing()する場合は、次の場所で入手可能なパッチを確認してください。file_scan_directoryをキャッシュする必要があります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.