QNetworkDiskCache: optimize expire()

- Use a std::vector<struct> that has the needed info already cached
  (e.g. now size() isn't computed twice)
- Only sort the cache items if the size exceeds the cache limit and
  there are files to remove

Change-Id: I69a7a5d1afb26d156c4babddf6b357ec68d569d1
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Ahmad Samir 2023-01-04 18:31:12 +02:00
parent 51b1a23aa1
commit 56e42f1818

View File

@ -16,7 +16,6 @@
#include <qurl.h> #include <qurl.h>
#include <qcryptographichash.h> #include <qcryptographichash.h>
#include <qdebug.h> #include <qdebug.h>
#include <QMultiMap>
#include <memory> #include <memory>
@ -483,47 +482,57 @@ qint64 QNetworkDiskCache::expire()
// close file handle to prevent "in use" error when QFile::remove() is called // close file handle to prevent "in use" error when QFile::remove() is called
d->lastItem.reset(); d->lastItem.reset();
QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot; const QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot;
QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories); QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories);
QMultiMap<QDateTime, QString> cacheItems; struct CacheItem
{
std::chrono::milliseconds msecs;
QString path;
qint64 size = 0;
};
std::vector<CacheItem> cacheItems;
qint64 totalSize = 0; qint64 totalSize = 0;
while (it.hasNext()) { while (it.hasNext()) {
QFileInfo info = it.nextFileInfo(); QFileInfo info = it.nextFileInfo();
QString path = info.filePath(); if (!info.fileName().endsWith(CACHE_POSTFIX))
QString fileName = info.fileName(); continue;
if (fileName.endsWith(CACHE_POSTFIX)) {
const QDateTime birthTime = info.birthTime(QTimeZone::UTC); QDateTime fileTime = info.birthTime(QTimeZone::UTC);
cacheItems.insert(birthTime.isValid() ? birthTime if (!fileTime.isValid())
: info.metadataChangeTime(QTimeZone::UTC), path); fileTime = info.metadataChangeTime(QTimeZone::UTC);
totalSize += info.size(); const std::chrono::milliseconds msecs{fileTime.toMSecsSinceEpoch()};
} const qint64 size = info.size();
cacheItems.push_back(CacheItem{msecs, info.filePath(), size});
totalSize += size;
} }
[[maybe_unused]] int removedFiles = 0; // used under QNETWORKDISKCACHE_DEBUG const qint64 goal = (maximumCacheSize() * 9) / 10;
qint64 goal = (maximumCacheSize() * 9) / 10; if (totalSize < goal)
QMultiMap<QDateTime, QString>::const_iterator i = cacheItems.constBegin(); return totalSize; // Nothing to do
while (i != cacheItems.constEnd()) {
if (totalSize < goal)
break;
QString name = i.value();
QFile file(name);
if (name.contains(PREPARED_SLASH)) { auto byFileTime = [&](const auto &a, const auto &b) { return a.msecs < b.msecs; };
for (QCacheItem *item : std::as_const(d->inserting)) { std::sort(cacheItems.begin(), cacheItems.end(), byFileTime);
if (item && item->file && item->file->fileName() == name) {
delete item->file; [[maybe_unused]] int removedFiles = 0; // used under QNETWORKDISKCACHE_DEBUG
item->file = nullptr; for (const CacheItem &cached : cacheItems) {
break; if (cached.path.contains(PREPARED_SLASH)) {
} auto matchesCacheItem = [&cached](QCacheItem *item) {
return item && item->file && item->file->fileName() == cached.path;
};
auto itemIt = std::find_if(d->inserting.cbegin(), d->inserting.cend(), matchesCacheItem);
if (itemIt != d->inserting.cend()) {
auto &tempfile = (*itemIt)->file;
delete tempfile;
tempfile = nullptr;
} }
} }
qint64 size = file.size(); QFile::remove(cached.path);
file.remove();
totalSize -= size;
++removedFiles; ++removedFiles;
++i; totalSize -= cached.size;
if (totalSize < goal)
break;
} }
#if defined(QNETWORKDISKCACHE_DEBUG) #if defined(QNETWORKDISKCACHE_DEBUG)
if (removedFiles > 0) { if (removedFiles > 0) {