Enable disk cache for files coming from resources

By storing the cached data in QStandardPaths::CacheDir + "/qmlcache/"
+ sha1(filename)

Change-Id: I6a8b4ca701019204fff362504697c3dac9f54bf1
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Simon Hausmann 2016-08-07 14:53:57 +02:00
parent f5a0531375
commit b40d005544
7 changed files with 58 additions and 13 deletions

View File

@ -68,7 +68,7 @@ public:
CompilationUnitMapper();
~CompilationUnitMapper();
CompiledData::Unit *open(const QString &sourcePath, QString *errorString);
CompiledData::Unit *open(const QString &cacheFilePath, const QString &sourcePath, QString *errorString);
void close();
private:

View File

@ -50,13 +50,11 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
CompiledData::Unit *CompilationUnitMapper::open(const QString &sourcePath, QString *errorString)
CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString)
{
close();
QByteArray cacheFileName = QFile::encodeName(sourcePath);
cacheFileName.append('c');
int fd = qt_safe_open(cacheFileName.constData(), O_RDONLY);
int fd = qt_safe_open(QFile::encodeName(cacheFileName).constData(), O_RDONLY);
if (fd == -1) {
*errorString = qt_error_string(errno);
return nullptr;

View File

@ -49,13 +49,12 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
CompiledData::Unit *CompilationUnitMapper::open(const QString &sourcePath, QString *errorString)
CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, const QString &sourcePath, QString *errorString)
{
close();
// ### TODO: fix up file encoding/normalization/unc handling once QFileSystemEntry
// is exported from QtCore.
const QString cacheFileName = sourcePath + QLatin1Char('c');
HANDLE handle =
#if defined(Q_OS_WINRT)
CreateFile2(reinterpret_cast<const wchar_t*>(cacheFileName.constData()),

View File

@ -56,6 +56,8 @@
#include <QFile>
#include <QFileInfo>
#include <QScopedValueRollback>
#include <QStandardPaths>
#include <QDir>
#endif
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
@ -321,6 +323,19 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0;
}
static QString cacheFilePath(const QUrl &url)
{
const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
const QString localCachePath = localSourcePath + QLatin1Char('c');
if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
return localCachePath;
QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
fileNameHash.addData(localSourcePath.toUtf8());
QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
QDir::root().mkpath(directory);
return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
}
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
{
errorString->clear();
@ -330,13 +345,13 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return false;
}
if (!unitUrl.isLocalFile()) {
if (!QQmlFile::isLocalFile(unitUrl)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
// Foo.qml -> Foo.qmlc
QSaveFile cacheFile(unitUrl.toLocalFile() + QLatin1Char('c'));
QSaveFile cacheFile(cacheFilePath(unitUrl));
if (!cacheFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
*errorString = cacheFile.errorString();
return false;
@ -371,7 +386,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
{
if (!url.isLocalFile()) {
if (!QQmlFile::isLocalFile(url)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
@ -379,10 +394,9 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory
const QString sourcePath = url.toLocalFile();
QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
CompiledData::Unit *mappedUnit = cacheFile->open(sourcePath, errorString);
if (!mappedUnit) {
CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
if (!mappedUnit)
return false;
}
const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);

View File

@ -4,4 +4,6 @@ osx:CONFIG -= app_bundle
SOURCES += tst_qmldiskcache.cpp
RESOURCES += test.qml
QT += core-private qml-private testlib

View File

@ -0,0 +1,4 @@
import QtQml 2.0
QtObject {
property int value: 20
}

View File

@ -38,6 +38,9 @@
#include <QQmlEngine>
#include <QQmlFileSelector>
#include <QThread>
#include <QCryptographicHash>
#include <QStandardPaths>
#include <QDirIterator>
class tst_qmldiskcache: public QObject
{
@ -52,6 +55,7 @@ private slots:
void recompileAfterChange();
void fileSelectors();
void localAliases();
void cacheResources();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@ -529,6 +533,30 @@ void tst_qmldiskcache::localAliases()
}
}
void tst_qmldiskcache::cacheResources()
{
const QString cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
QVERIFY(QDir::root().mkpath(cacheDirectory));
const QString qmlCacheDirectory = cacheDirectory + QLatin1String("/qmlcache/");
QVERIFY(QDir(qmlCacheDirectory).removeRecursively());
QVERIFY(QDir::root().mkpath(qmlCacheDirectory));
QVERIFY(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot).isEmpty());
QQmlEngine engine;
{
CleanlyLoadingComponent component(&engine, QUrl("qrc:/test.qml"));
qDebug() << component.errorString();
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 20);
}
QCOMPARE(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot | QDir::Files).count(), 1);
}
QTEST_MAIN(tst_qmldiskcache)
#include "tst_qmldiskcache.moc"