From 26c742c1e1c96740646bb1896df52bad2fbe105d Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 29 Jul 2020 13:04:33 +0200 Subject: [PATCH] QFileSystemModel: make sure files are stat'ed in the worker thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QFileInfoGatherer creates QFileInfo objects in the worker thread to offload the work from the UI thread, but it never calls any methods on the QFileInfo objects that would trigger a stat'ing of the files. For large directories on remote file system, that easily results in the UI thread being blocked for a very long time. Add a private 'stat' method to QFileInfo which allows forcing it to stat all attributes from the worker thread, and make QFileInfoGatherer a friend so that it can call the function from the worker thread. This way, QFileSystemModel can access the cached data for each QFileInfo object, without having to touch the file system from the UI thread. Also reduce the amount of signal emissions for drive information, batch all drives (which can safely be assumed to be at most a two digit figure) into a single emission instead. Change-Id: Ifdcae150406187db9984d0fec9add93597b5f85b Fixes: QTBUG-41373 Pick-to: 5.15 Reviewed-by: Edward Welbourne Reviewed-by: MÃ¥rten Nordheim --- src/corelib/io/qfileinfo.cpp | 19 ++++++++++++++++++- src/corelib/io/qfileinfo.h | 4 +++- src/widgets/dialogs/qfileinfogatherer.cpp | 16 +++++++++++----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index fb5aeac1898..062efcf40ae 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -1558,6 +1558,23 @@ void QFileInfo::setCaching(bool enable) d->cache_enabled = enable; } +/*! + \internal + + Reads all attributes from the file system. + + This is useful when information about the file system is collected in a + worker thread, and then passed to the UI in the form of caching QFileInfo + instances. + + \sa setCaching(), refresh() +*/ +void QFileInfo::stat() +{ + Q_D(QFileInfo); + QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AllMetaDataFlags); +} + /*! \typedef QFileInfoList \relates QFileInfo diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h index 2bed64eb1ac..d7cc51c7dff 100644 --- a/src/corelib/io/qfileinfo.h +++ b/src/corelib/io/qfileinfo.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -189,6 +189,8 @@ protected: QSharedDataPointer d_ptr; private: + friend class QFileInfoGatherer; + void stat(); QFileInfoPrivate* d_func(); inline const QFileInfoPrivate* d_func() const { diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp index 750db9a2dce..11d963226f0 100644 --- a/src/widgets/dialogs/qfileinfogatherer.cpp +++ b/src/widgets/dialogs/qfileinfogatherer.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -40,6 +40,7 @@ #include "qfileinfogatherer_p.h" #include #include +#include #ifndef Q_OS_WIN # include # include @@ -378,12 +379,15 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil for (const auto &file : files) infoList << QFileInfo(file); } + QList> updatedFiles; + updatedFiles.reserve(infoList.count()); for (int i = infoList.count() - 1; i >= 0; --i) { - QString driveName = translateDriveName(infoList.at(i)); - QList> updatedFiles; - updatedFiles.append(QPair(driveName, infoList.at(i))); - emit updates(path, updatedFiles); + QFileInfo driveInfo = infoList.at(i); + driveInfo.stat(); + QString driveName = translateDriveName(driveInfo); + updatedFiles.append(QPair(driveName, driveInfo)); } + emit updates(path, updatedFiles); return; } @@ -400,6 +404,7 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil while (!abort.loadRelaxed() && dirIt.hasNext()) { dirIt.next(); fileInfo = dirIt.fileInfo(); + fileInfo.stat(); allFiles.append(fileInfo.fileName()); fetch(fileInfo, base, firstTime, updatedFiles, path); } @@ -411,6 +416,7 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil while (!abort.loadRelaxed() && filesIt != filesToCheck.constEnd()) { fileInfo.setFile(path + QDir::separator() + *filesIt); ++filesIt; + fileInfo.stat(); fetch(fileInfo, base, firstTime, updatedFiles, path); } if (!updatedFiles.isEmpty())