QStorageInfo/Linux: avoid parsing /proc/self/mountinfo N+1 times

Mine has 41 lines, of which 22 are returned by parseMountInfo with
filtering. That meant the file was parsed once to get the listing, then
22 times more to create a QStorageInfo for each entry. Now
QStorageInfo::mountedVolumes() opens the file and parses it only once.

Pick-to: 6.6
Change-Id: I9d43e5b91eb142d6945cfffd178752ef6c2122f2
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
This commit is contained in:
Thiago Macieira 2023-09-22 13:36:12 -07:00
parent 3f2b54f0a1
commit c82ed8b279
5 changed files with 37 additions and 25 deletions

View File

@ -37,6 +37,11 @@ QT_IMPL_METATYPE_EXTERN(QStorageInfo)
\snippet code/src_corelib_io_qstorageinfo.cpp 2
*/
QStorageInfo::QStorageInfo(QStorageInfoPrivate &dd)
: d(&dd)
{
}
/*!
Constructs an empty QStorageInfo object.

View File

@ -56,6 +56,7 @@ public:
static QStorageInfo root();
private:
explicit QStorageInfo(QStorageInfoPrivate &dd);
friend class QStorageInfoPrivate;
friend inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
{

View File

@ -164,12 +164,12 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
QList<QStorageInfo> volumes;
for (MountInfo &info : infos) {
QStorageInfo storage(info.mountPoint);
storage.d->device = info.device;
storage.d->fileSystemType = info.fsType;
storage.d->subvolume = info.fsRoot;
QStorageInfoPrivate d(std::move(info));
d.retrieveVolumeInfo();
QStorageInfo storage(*new QStorageInfoPrivate(std::move(d)));
if (storage.bytesTotal() == 0 && storage != root())
continue;
storage.d->name = retrieveLabel(storage.d->device);
volumes.push_back(storage);
}
return volumes;

View File

@ -29,6 +29,7 @@
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
using MountInfo = QStorageInfoPrivate::MountInfo;
static const char MountInfoPath[] = "/proc/self/mountinfo";
@ -152,16 +153,6 @@ static void tokenizeLine(std::array<QByteArrayView, FieldCount> &fields, QByteAr
}
}
namespace {
struct MountInfo {
QString mountPoint;
QByteArray fsType;
QByteArray device;
QByteArray fsRoot;
dev_t stDev = 0;
};
}
// parseMountInfo() is called from:
// - QStorageInfoPrivate::initRootPath(), where a list of all mounted volumes is needed
// - QStorageInfoPrivate::mountedVolumes(), where some filesystem types are ignored

View File

@ -28,10 +28,7 @@ inline Q_LOGGING_CATEGORY(lcStorageInfo, "qt.core.qstorageinfo", QtWarningMsg)
class QStorageInfoPrivate : public QSharedData
{
public:
inline QStorageInfoPrivate() : QSharedData(),
bytesTotal(-1), bytesFree(-1), bytesAvailable(-1), blockSize(-1),
readOnly(false), ready(false), valid(false)
{}
QStorageInfoPrivate() = default;
void initRootPath();
void doStat();
@ -59,6 +56,24 @@ protected:
void retrieveLabel();
#elif defined(Q_OS_UNIX)
void retrieveVolumeInfo();
# ifdef Q_OS_LINUX
public:
struct MountInfo {
QString mountPoint;
QByteArray fsType;
QByteArray device;
QByteArray fsRoot;
dev_t stDev = 0;
};
QStorageInfoPrivate(MountInfo &&info)
: rootPath(std::move(info.mountPoint)),
device(std::move(info.device)),
subvolume(std::move(info.fsRoot)),
fileSystemType(std::move(info.fsType))
{
}
# endif
#endif
public:
@ -68,14 +83,14 @@ public:
QByteArray fileSystemType;
QString name;
qint64 bytesTotal;
qint64 bytesFree;
qint64 bytesAvailable;
ulong blockSize;
qint64 bytesTotal = -1;
qint64 bytesFree = -1;
qint64 bytesAvailable = -1;
ulong blockSize = ulong(-1);
bool readOnly;
bool ready;
bool valid;
bool readOnly = false;
bool ready = false;
bool valid = false;
};
// Common helper functions