QFileSystemModel: make sure files are stat'ed in the worker thread

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 <edward.welbourne@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Volker Hilsheimer 2020-07-29 13:04:33 +02:00
parent c5da2e6f06
commit 26c742c1e1
3 changed files with 32 additions and 7 deletions

View File

@ -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

View File

@ -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<QFileInfoPrivate> d_ptr;
private:
friend class QFileInfoGatherer;
void stat();
QFileInfoPrivate* d_func();
inline const QFileInfoPrivate* d_func() const
{

View File

@ -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 <qdebug.h>
#include <qdiriterator.h>
#include <private/qfileinfo_p.h>
#ifndef Q_OS_WIN
# include <unistd.h>
# include <sys/types.h>
@ -378,12 +379,15 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil
for (const auto &file : files)
infoList << QFileInfo(file);
}
QList<QPair<QString, QFileInfo>> updatedFiles;
updatedFiles.reserve(infoList.count());
for (int i = infoList.count() - 1; i >= 0; --i) {
QString driveName = translateDriveName(infoList.at(i));
QList<QPair<QString, QFileInfo>> updatedFiles;
updatedFiles.append(QPair<QString,QFileInfo>(driveName, infoList.at(i)));
emit updates(path, updatedFiles);
QFileInfo driveInfo = infoList.at(i);
driveInfo.stat();
QString driveName = translateDriveName(driveInfo);
updatedFiles.append(QPair<QString,QFileInfo>(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())