file_scan_directory () виконує близько 10 секунд


10

Використовуючи xhprof, я зауважив, що file_scan_directory()для завантаження передньої сторінки потрібно більше 10 секунд. Чому це повинно пройти так довго?

Це вихід xhprofile:

скріншот


Ви не можете "file_scan_directory" "передню сторінку", оскільки титульна сторінка - це запис у таблиці бази даних, а не шлях до файлової системи.
Летаріон

@Letharion Я думаю, ви неправильно зрозуміли моє запитання. Я маю на увазі час, який ця функція займає, коли завантажується головна сторінка. Я редагував питання.
hknik

Чи справді титульна сторінка має щось спільне з функцією, яка займає певний час? Який каталог ви насправді скануєте? Що в каталозі?
Летаріон

Ага! Я думав, що ти сам зателефонував у цю функцію і цікавився, чому ти не надав більше деталей. Відповідь Бердіра виглядає дуже обґрунтованою. :)
Летаріон

Відповіді:


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 (), який викликає цю функцію, якщо він не може знайти потрібний файл. Додайте dpm (func_get_args ()) прямо перед тим, як він викличе drupal_system_listing (), який повинен повідомити, який файл ви не знайдете.


Ні. На жаль (!) Жоден модуль не відсутній у файловій системі
hknik

Тоді вам потрібно простежити, звідки надходить дзвінок, можливо, користувацький або модуль допису чинить щось не так. Клацніть по батьківських функціях file_scan_directory () та оновіть початкову публікацію зі списком батьківських функцій.
Бердір

Дивлячись на ці функції, це дійсно схоже , що це не вистачає модуля або , може бути , один файл модуля. Подивіться на drupal_get_filename: api.drupal.org/api/drupal/includes!bootstrap.inc/function/… . Він дійсно викликає функцію, якщо не може знайти потрібний файл. Додайте dpm (func_get_args ()) прямо перед тим, як він викличе drupal_system_listing (), який повинен повідомити, яку функцію ви не знайдете.
Бердір

@Berdir Ваш останній коментар повинен бути у вашій відповіді, оскільки це актуально.
kiamlaluno

Посилання на "відому проблему в Drupal 7" та "Уникати каталогу модулів повторного сканування" порушені. Обидва є колишніми відповідями на зміну ставок Хтось має інші посилання?
rfay

4

Є декілька причин, через які може виникнути це питання, і на превеликий жаль, я зараз знаю себе з цих причин. Розчаровуючи, якщо ви щойно помітили цю проблему після оновлення ядра Drupal до 7,33+, це може бути помилковим помилкою в будь-якому модулі, навіть якщо ви не оновили цей модуль.

Модулі вилучені з кодової бази

Ви можете спочатку перевірити відому помилку, яку згадує @Berdir, особливо якщо ви нещодавно видаляли "невикористані" модулі з кодової бази. Щоб дізнатись, чи є у вас модулі, які увімкнено, але вилучені з файлової системи, ви можете запустити такий сценарій, як зазначений тут, - або використовувати шахту, написану для встановлення на декількох сайтах із системою друку. з базового каталогу 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 (з коментаря 19 у випуску № 1082892) або невдалим друком у модулі чи темі , наприклад imagecache_actions(див. https://drupal.org/node/2381357 ).

У будь-якому випадку, щоб зрозуміти, чому саме це відбувається, потрібно точно знати, який файл Drupal не може знайти. Таким чином, відповідно з коментарем Berdir, ви можете тимчасово зламати drupal_get_filenameв bootstrap.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папка huuge, вбудована в мою власну тему, для gulpтого, щоб було скановано кожну флеш-кеш. Переміщення цих файлів із папки теми (та оновлення деяких шляхів у моєму gulpfile), здавалося, вирішило це для мене. Як варіант: я думаю, ви можете зламати file.inc:

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


0

Це file_scan_directory()рекурсивна функція, яка відповідає всім файлам для заданої директорії. Це використання is_dir()та opendir()PHP-дзвінки, що може бути найдорожчим у зв'язку з системними дзвінками вводу-виводу. Простий завантажувальний пристрій Drupal (наприклад time drush ev "") може викликати file_scan_directoryкілька тисяч разів (залежно від складності вашої ієрархії папок Drupal, наприклад, кількості модулів та його папок).

У моєму випадку я мав ~ 1500 дзвінків в file_scan_directory(24 секунд в цілому , що складаються з 2 -х викликів drupal_system_listingв common.inc, то інші виклики були розділені рекурсивними викликами file_scan_directoryІт-я.

Щоб підвищити продуктивність дзвінків вводу-виводу, вам потрібно здійснити кешування файлів. Цього можна досягти, встановивши та включивши 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 за допомогою dtrace(за допомогою статичних зондів PHP 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 слід кешувати .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.