]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Optimize Directory size counting
authorMéven Car <meven.car@kdemail.net>
Sun, 12 Feb 2023 11:21:53 +0000 (11:21 +0000)
committerMéven Car <meven.car@kdemail.net>
Sun, 12 Feb 2023 11:21:53 +0000 (11:21 +0000)
Two changes:
 * Prioritise size counting for visible path
 * stop the worker when switching dirs

src/kitemviews/kfileitemmodelrolesupdater.cpp
src/kitemviews/kfileitemmodelrolesupdater.h
src/kitemviews/private/kdirectorycontentscounter.cpp
src/kitemviews/private/kdirectorycontentscounter.h
src/kitemviews/private/kdirectorycontentscounterworker.cpp
src/kitemviews/private/kdirectorycontentscounterworker.h

index 4af4f30243f5a5928c62c118430f6748650491cd..4fd12661998233aaf0ce58ad58b98249463615e7 100644 (file)
@@ -422,6 +422,10 @@ void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList &itemRang
         m_hoverSequenceLoadedItems.clear();
 
         killPreviewJob();
+
+        if (m_scanDirectories) {
+            m_directoryContentsCounter->stopWorker();
+        }
     } else {
         // Only remove the items from m_finishedItems. They will be removed
         // from the other sets later on.
@@ -537,7 +541,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem &item, const QPi
 
     QPixmap scaledPixmap = transformPreviewPixmap(pixmap);
 
-    QHash<QByteArray, QVariant> data = rolesData(item);
+    QHash<QByteArray, QVariant> data = rolesData(item, index);
 
     const QStringList overlays = data["iconOverlays"].toStringList();
     // Strangely KFileItem::overlays() returns empty string-values, so
@@ -1210,13 +1214,10 @@ void KFileItemModelRolesUpdater::applySortRole(int index)
 
         data.insert("type", item.mimeComment());
     } else if (m_model->sortRole() == "size" && item.isLocalFile() && !item.isSlow() && item.isDir()) {
-        const QString path = item.localPath();
-        if (m_scanDirectories) {
-            m_directoryContentsCounter->scanDirectory(path);
-        }
+        startDirectorySizeCounting(item, index);
     } else {
         // Probably the sort role is a baloo role - just determine all roles.
-        data = rolesData(item);
+        data = rolesData(item, index);
     }
 
     disconnect(m_model, &KFileItemModel::itemsChanged, this, &KFileItemModelRolesUpdater::slotItemsChanged);
@@ -1252,7 +1253,7 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint)
 
         QHash<QByteArray, QVariant> data;
         if (resolveAll) {
-            data = rolesData(item);
+            data = rolesData(item, index);
         }
 
         if (!item.iconName().isEmpty()) {
@@ -1273,7 +1274,19 @@ bool KFileItemModelRolesUpdater::applyResolvedRoles(int index, ResolveHint hint)
     return false;
 }
 
-QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem &item)
+void KFileItemModelRolesUpdater::startDirectorySizeCounting(const KFileItem &item, int index)
+{
+    // Tell m_directoryContentsCounter that we want to count the items
+    // inside the directory. The result will be received in slotDirectoryContentsCountReceived.
+    if (m_scanDirectories && item.isLocalFile()) {
+        const QString path = item.localPath();
+        const auto priority = index >= m_firstVisibleIndex && index <= m_lastVisibleIndex ? KDirectoryContentsCounter::PathCountPriority::High
+                                                                                          : KDirectoryContentsCounter::PathCountPriority::Normal;
+        m_directoryContentsCounter->scanDirectory(path, priority);
+    }
+}
+
+QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem &item, int index)
 {
     QHash<QByteArray, QVariant> data;
 
@@ -1281,16 +1294,7 @@ QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileIte
     const bool getIsExpandableRole = m_roles.contains("isExpandable");
 
     if ((getSizeRole || getIsExpandableRole) && !item.isSlow() && item.isDir()) {
-        if (item.isLocalFile()) {
-            // Tell m_directoryContentsCounter that we want to count the items
-            // inside the directory. The result will be received in slotDirectoryContentsCountReceived.
-            if (m_scanDirectories) {
-                const QString path = item.localPath();
-                m_directoryContentsCounter->scanDirectory(path);
-            }
-        } else if (getSizeRole) {
-            data.insert("size", -1); // -1 indicates an unknown number of items
-        }
+        startDirectorySizeCounting(item, index);
     }
 
     if (m_roles.contains("extension")) {
index 90f29c5c0acedd68387544cb84346e81923c974e..be6f2319311cbb56520be4a903f654193d6757b9 100644 (file)
@@ -319,7 +319,7 @@ private:
 
     enum ResolveHint { ResolveFast, ResolveAll };
     bool applyResolvedRoles(int index, ResolveHint hint);
-    QHash<QByteArray, QVariant> rolesData(const KFileItem &item);
+    QHash<QByteArray, QVariant> rolesData(const KFileItem &item, int index);
 
     /**
      * Must be invoked if a property has been changed that affects
@@ -334,6 +334,8 @@ private:
     void trimHoverSequenceLoadedItems();
 
 private:
+    void startDirectorySizeCounting(const KFileItem &item, int index);
+
     enum State { Idle, Paused, ResolvingSortRole, ResolvingAllRoles, PreviewJobRunning };
 
     State m_state;
index 039b79b6e692d68eef5cf137f28055903e40944f..37e852ab9eea2b210b8196ae3dcd972bc609a8ef 100644 (file)
@@ -44,6 +44,7 @@ KDirectoryContentsCounter::KDirectoryContentsCounter(KFileItemModel *model, QObj
     m_worker->moveToThread(m_workerThread);
 
     connect(this, &KDirectoryContentsCounter::requestDirectoryContentsCount, m_worker, &KDirectoryContentsCounterWorker::countDirectoryContents);
+    connect(this, &KDirectoryContentsCounter::stop, m_worker, &KDirectoryContentsCounterWorker::stop);
     connect(m_worker, &KDirectoryContentsCounterWorker::result, this, &KDirectoryContentsCounter::slotResult);
 
     m_dirWatcher = new KDirWatch(this);
@@ -71,11 +72,6 @@ KDirectoryContentsCounter::~KDirectoryContentsCounter()
     }
 }
 
-void KDirectoryContentsCounter::scanDirectory(const QString &path)
-{
-    startWorker(path);
-}
-
 void KDirectoryContentsCounter::slotResult(const QString &path, int count, long size)
 {
     m_workerIsBusy = false;
@@ -91,11 +87,11 @@ void KDirectoryContentsCounter::slotResult(const QString &path, int count, long
     if (!m_priorityQueue.empty()) {
         const QString firstPath = m_priorityQueue.front();
         m_priorityQueue.pop_front();
-        startWorker(firstPath);
+        scanDirectory(firstPath, PathCountPriority::High);
     } else if (!m_queue.empty()) {
         const QString firstPath = m_queue.front();
         m_queue.pop_front();
-        startWorker(firstPath);
+        scanDirectory(firstPath, PathCountPriority::Normal);
     }
 
     if (s_cache->contains(resolvedPath)) {
@@ -127,7 +123,7 @@ void KDirectoryContentsCounter::slotDirWatchDirty(const QString &path)
             return;
         }
 
-        startWorker(path);
+        scanDirectory(path, PathCountPriority::High);
     }
 }
 
@@ -156,7 +152,7 @@ void KDirectoryContentsCounter::slotItemsRemoved()
     }
 }
 
-void KDirectoryContentsCounter::startWorker(const QString &path)
+void KDirectoryContentsCounter::scanDirectory(const QString &path, PathCountPriority priority)
 {
     const QString resolvedPath = QFileInfo(path).canonicalFilePath();
     const bool alreadyInCache = s_cache->contains(resolvedPath);
@@ -168,10 +164,16 @@ void KDirectoryContentsCounter::startWorker(const QString &path)
     }
 
     if (m_workerIsBusy) {
+        // only enqueue path not yet in queue
         if (std::find(m_queue.begin(), m_queue.end(), path) == m_queue.end()
             && std::find(m_priorityQueue.begin(), m_priorityQueue.end(), path) == m_priorityQueue.end()) {
-            if (alreadyInCache) {
-                m_queue.push_back(path);
+            if (priority == PathCountPriority::Normal) {
+                if (alreadyInCache) {
+                    // if we already knew the dir size, it gets lower priority
+                    m_queue.push_back(path);
+                } else {
+                    m_queue.push_front(path);
+                }
             } else {
                 // append to priority queue
                 m_priorityQueue.push_back(path);
@@ -193,4 +195,11 @@ void KDirectoryContentsCounter::startWorker(const QString &path)
     }
 }
 
+void KDirectoryContentsCounter::stopWorker()
+{
+    m_queue.clear();
+    m_priorityQueue.clear();
+    Q_EMIT stop();
+}
+
 QThread *KDirectoryContentsCounter::m_workerThread = nullptr;
index f74565b73af48b29d893a17957b26da13e1ba6c8..9a5e4a86b333f1dbb156a3071abc3c6048d2d6c9 100644 (file)
@@ -21,6 +21,8 @@ class KDirectoryContentsCounter : public QObject
     Q_OBJECT
 
 public:
+    enum PathCountPriority { Normal, High };
+
     explicit KDirectoryContentsCounter(KFileItemModel *model, QObject *parent = nullptr);
     ~KDirectoryContentsCounter() override;
 
@@ -35,7 +37,12 @@ public:
      * Uses a cache internally to speed up first result,
      * but emit again result when the cache was updated
      */
-    void scanDirectory(const QString &path);
+    void scanDirectory(const QString &path, PathCountPriority priority);
+
+    /**
+     * Stops the work until new input is passed
+     */
+    void stopWorker();
 
 Q_SIGNALS:
     /**
@@ -46,14 +53,13 @@ Q_SIGNALS:
 
     void requestDirectoryContentsCount(const QString &path, KDirectoryContentsCounterWorker::Options options);
 
+    void stop();
+
 private Q_SLOTS:
     void slotResult(const QString &path, int count, long size);
     void slotDirWatchDirty(const QString &path);
     void slotItemsRemoved();
 
-private:
-    void startWorker(const QString &path);
-
 private:
     KFileItemModel *m_model;
 
index e227c1bc6895815733042b152e210c6264dfd8c9..2227ebbc262953fb7ad7d1373ebde61282232c99 100644 (file)
@@ -25,7 +25,7 @@ KDirectoryContentsCounterWorker::KDirectoryContentsCounterWorker(QObject *parent
 
 #ifndef Q_OS_WIN
 KDirectoryContentsCounterWorker::CountResult
-walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel)
+KDirectoryContentsCounterWorker::walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel)
 {
     int count = -1;
     long size = -1;
@@ -36,7 +36,7 @@ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDir
         QT_DIRENT *dirEntry;
         QT_STATBUF buf;
 
-        while ((dirEntry = QT_READDIR(dir))) {
+        while (!m_stopping && (dirEntry = QT_READDIR(dir))) {
             if (dirEntry->d_name[0] == '.') {
                 if (dirEntry->d_name[1] == '\0' || !countHiddenFiles) {
                     // Skip "." or hidden files
@@ -64,7 +64,7 @@ walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDir
                         size += buf.st_size;
                     }
                 }
-                if (dirEntry->d_type == DT_DIR) {
+                if (!m_stopping && dirEntry->d_type == DT_DIR) {
                     // recursion for dirs
                     auto subdirResult = walkDir(nameBuf, countHiddenFiles, countDirectoriesOnly, allowedRecursiveLevel - 1);
                     if (subdirResult.size > 0) {
@@ -106,8 +106,18 @@ KDirectoryContentsCounterWorker::CountResult KDirectoryContentsCounterWorker::su
 #endif
 }
 
+void KDirectoryContentsCounterWorker::stop()
+{
+    m_stopping = true;
+}
+
 void KDirectoryContentsCounterWorker::countDirectoryContents(const QString &path, Options options)
 {
+    m_stopping = false;
+
     auto res = subItemsCount(path, options);
-    Q_EMIT result(path, res.count, res.size);
+
+    if (!m_stopping) {
+        Q_EMIT result(path, res.count, res.size);
+    }
 }
index 6bbe099a5650138a018b512380ed2d8aed77636c..5266960cd39f88438de177d4bf258de45a835d27 100644 (file)
@@ -36,7 +36,7 @@ public:
      *
      * @return The number of items.
      */
-    static CountResult subItemsCount(const QString &path, Options options);
+    CountResult subItemsCount(const QString &path, Options options);
 
 Q_SIGNALS:
     /**
@@ -53,6 +53,15 @@ public Q_SLOTS:
     // is needed here. Just using 'Options' is OK for the compiler, but
     // confuses moc.
     void countDirectoryContents(const QString &path, KDirectoryContentsCounterWorker::Options options);
+    void stop();
+
+private:
+#ifndef Q_OS_WIN
+    KDirectoryContentsCounterWorker::CountResult
+    walkDir(const QString &dirPath, const bool countHiddenFiles, const bool countDirectoriesOnly, const uint allowedRecursiveLevel);
+#endif
+
+    bool m_stopping = false;
 };
 
 Q_DECLARE_METATYPE(KDirectoryContentsCounterWorker::Options)