diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-03-15 16:52:10 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-03-21 21:54:06 +0000 |
commit | 5ce2235f425b3c5047faf709c87c9b5c8e414b8b (patch) | |
tree | 5bd74cf139185d284a9379f095e31e0b8f1b6f36 | |
parent | fc0254a48c775cdfea693402d0472b73c8b940e5 (diff) |
Avoid reading (not parsing) .qml files when using the cache
By making SourceCodeData copyable we can delay the reading of the source
file until we really need to. This also allows persisting the QFileInfo
object and therefore having only one stat() call to check if the file
exists, what its size is and what the last modification time is.
Change-Id: Ic7e4d5f566d870f3b1fa8302227417fa813cb139
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 78 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 12 |
2 files changed, 54 insertions, 36 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 193239e680..c5d4945bf1 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1246,8 +1246,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) { QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; - d.inlineSourceCodeOrFileName = QString::fromUtf8(data); - d.sourceCodeAvailable = true; + d.inlineSourceCode = QString::fromUtf8(data); setData(blob, d); } @@ -1255,8 +1254,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) { QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::SourceCodeData d; - d.inlineSourceCodeOrFileName = fileName; - d.sourceCodeAvailable = false; + d.fileInfo = QFileInfo(fileName); setData(blob, d); } @@ -2237,7 +2235,7 @@ void QQmlTypeData::done() qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); if (!loadFromSource()) return; - m_backupSourceCode.clear(); + m_backupSourceCode = SourceCodeData(); m_compiledData = nullptr; } @@ -2346,11 +2344,7 @@ bool QQmlTypeData::loadImplicitImport() void QQmlTypeData::dataReceived(const SourceCodeData &data) { - QString error; - m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp); - // if we failed to read the source code, process it _after_ we've tried - // to use the disk cache, in order to support scenarios where the source - // was removed deliberately. + m_backupSourceCode = data; if (tryLoadFromDiskCache()) return; @@ -2358,8 +2352,8 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data) if (isError()) return; - if (!error.isEmpty()) { - setError(error); + if (!m_backupSourceCode.exists()) { + setError(QQmlTypeLoader::tr("No such file or directory")); return; } @@ -2379,10 +2373,18 @@ void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *un bool QQmlTypeData::loadFromSource() { m_document.reset(new QmlIR::Document(isDebugging())); - m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp; + m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp(); QQmlEngine *qmlEngine = typeLoader()->engine(); QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); - if (!compiler.generateFromQml(m_backupSourceCode, finalUrlString(), m_document.data())) { + + QString sourceError; + const QString source = m_backupSourceCode.readAll(&sourceError); + if (!sourceError.isEmpty()) { + setError(sourceError); + return false; + } + + if (!compiler.generateFromQml(source, finalUrlString(), m_document.data())) { QList<QQmlError> errors; errors.reserve(compiler.errors.count()); for (const QQmlJS::DiagnosticMessage &msg : qAsConst(compiler.errors)) { @@ -2891,8 +2893,9 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) QmlIR::Document irUnit(isDebugging()); + irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp(); QString error; - QString source = data.readAll(&error, &irUnit.jsModule.sourceTimeStamp); + QString source = data.readAll(&error); if (!error.isEmpty()) { setError(error); return; @@ -3071,28 +3074,19 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit * Q_UNIMPLEMENTED(); } -QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTimeStamp) const +QString QQmlDataBlob::SourceCodeData::readAll(QString *error) const { error->clear(); - if (sourceCodeAvailable) { - if (sourceTimeStamp) - *sourceTimeStamp = 0; - return inlineSourceCodeOrFileName; - } - QFile f(inlineSourceCodeOrFileName); + if (!inlineSourceCode.isEmpty()) + return inlineSourceCode; + + QFile f(fileInfo.absoluteFilePath()); if (!f.open(QIODevice::ReadOnly)) { *error = f.errorString(); return QString(); } - if (sourceTimeStamp) { - QDateTime timeStamp = QFileInfo(f).lastModified(); - // Files from the resource system do not have any time stamps, so fall back to the application - // executable. - if (!timeStamp.isValid()) - timeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); - *sourceTimeStamp = timeStamp.toMSecsSinceEpoch(); - } - QByteArray data(f.size(), Qt::Uninitialized); + + QByteArray data(fileInfo.size(), Qt::Uninitialized); if (f.read(data.data(), data.length()) != data.length()) { *error = f.errorString(); return QString(); @@ -3100,6 +3094,28 @@ QString QQmlDataBlob::SourceCodeData::readAll(QString *error, qint64 *sourceTime return QString::fromUtf8(data); } +qint64 QQmlDataBlob::SourceCodeData::sourceTimeStamp() const +{ + if (!inlineSourceCode.isEmpty()) + return 0; + + QDateTime timeStamp = fileInfo.lastModified(); + if (timeStamp.isValid()) + return timeStamp.toMSecsSinceEpoch(); + + static qint64 appTimeStamp = 0; + if (appTimeStamp == 0) + appTimeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified().toMSecsSinceEpoch(); + return appTimeStamp; +} + +bool QQmlDataBlob::SourceCodeData::exists() const +{ + if (!inlineSourceCode.isEmpty()) + return true; + return fileInfo.exists(); +} + QT_END_NAMESPACE #include "qqmltypeloader.moc" diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index c1b3548fa6..0bae857874 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -54,6 +54,7 @@ #include <QtQml/qtqmlglobal.h> #include <QtCore/qobject.h> #include <QtCore/qatomic.h> +#include <QtCore/qfileinfo.h> #if QT_CONFIG(qml_network) #include <QtNetwork/qnetworkreply.h> #endif @@ -132,12 +133,14 @@ public: class SourceCodeData { public: - QString readAll(QString *error, qint64 *sourceTimeStamp = 0) const; + QString readAll(QString *error) const; + qint64 sourceTimeStamp() const; + bool exists() const; private: friend class QQmlDataBlob; friend class QQmlTypeLoader; - QString inlineSourceCodeOrFileName; - bool sourceCodeAvailable = false; + QString inlineSourceCode; + QFileInfo fileInfo; }; protected: @@ -460,8 +463,7 @@ private: void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override; - qint64 m_sourceTimeStamp = 0; - QString m_backupSourceCode; // used when cache verification fails. + SourceCodeData m_backupSourceCode; // used when cache verification fails. QScopedPointer<QmlIR::Document> m_document; QV4::CompiledData::TypeReferenceMap m_typeReferences; |