FolderMan: Remove assumption of unique running sync
authorChristian Kamm <mail@ckamm.de>
Thu, 26 Nov 2020 16:19:20 +0000 (17:19 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:21 +0000 (10:58 +0100)
src/gui/accountsettings.cpp
src/gui/folder.cpp
src/gui/folder.h
src/gui/folderman.cpp
src/gui/folderman.h
src/gui/folderstatusmodel.cpp
src/gui/owncloudgui.cpp

index e7d77e4b1604f36551dfd1e84180e4faffce18a7..9f06e2d623da3960097132c7bcc40f58bfdf1cfc 100644 (file)
@@ -426,7 +426,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)
 
     if (!folderPaused) {
         ac = menu->addAction(tr("Force sync now"));
-        if (folderMan->currentSyncFolder() == folder) {
+        if (folder && folder->isSyncRunning()) {
             ac->setText(tr("Restart sync"));
         }
         ac->setEnabled(folderConnected);
@@ -738,9 +738,11 @@ void AccountSettings::slotForceSyncCurrentFolder()
     FolderMan *folderMan = FolderMan::instance();
     if (auto selectedFolder = folderMan->folder(selectedFolderAlias())) {
         // Terminate and reschedule any running sync
-        if (Folder *current = folderMan->currentSyncFolder()) {
-            folderMan->terminateSyncProcess();
-            folderMan->scheduleFolder(current);
+        for (auto f : folderMan->map()) {
+            if (f->isSyncRunning()) {
+                f->slotTerminateSync();
+                folderMan->scheduleFolder(f);
+            }
         }
 
         selectedFolder->slotWipeErrorBlacklist(); // issue #6757
index ebe9feb91c768f5125591a3a989153d0cb2f91c4..6951c9b11fd91d172cbb2ed7f6ea2a5c66353369 100644 (file)
@@ -221,6 +221,11 @@ bool Folder::isBusy() const
     return _engine->isSyncRunning();
 }
 
+bool Folder::isSyncRunning() const
+{
+    return _engine->isSyncRunning();
+}
+
 QString Folder::remotePath() const
 {
     return _definition.targetPath;
index 8d4ab1915e10d59926343b11800c35f391141c03..a5b0641c99b8156ac87b3d7ac7a3d904e74fe08e 100644 (file)
@@ -164,6 +164,9 @@ public:
      */
     virtual bool isBusy() const;
 
+    /** True if the folder is currently synchronizing */
+    bool isSyncRunning() const;
+
     /**
      * return the last sync result with error message and status
      */
index 5a3a5fbf63bad0a17120f8e0a558ca0b9e31fa3d..63e971c0f368d1a02e5e8a76c187465cd6c52ec1 100644 (file)
@@ -541,19 +541,6 @@ void FolderMan::slotFolderCanSyncChanged()
     }
 }
 
-// this really terminates the current sync process
-// ie. no questions, no prisoners
-// csync still remains in a stable state, regardless of that.
-void FolderMan::terminateSyncProcess()
-{
-    Folder *f = _currentSyncFolder;
-    if (f) {
-        // This will, indirectly and eventually, call slotFolderSyncFinished
-        // and thereby clear _currentSyncFolder.
-        f->slotTerminateSync();
-    }
-}
-
 Folder *FolderMan::folder(const QString &alias)
 {
     if (!alias.isEmpty()) {
@@ -665,7 +652,7 @@ void FolderMan::slotRunOneEtagJob()
             //qCDebug(lcFolderMan) << "No more remote ETag check jobs to schedule.";
 
             /* now it might be a good time to check for restarting... */
-            if (!_currentSyncFolder && _appRestartRequired) {
+            if (!isAnySyncRunning() && _appRestartRequired) {
                 restartApplication();
             }
         } else {
@@ -697,9 +684,12 @@ void FolderMan::slotAccountStateChanged()
         qCInfo(lcFolderMan) << "Account" << accountName << "disconnected or paused, "
                                                            "terminating or descheduling sync folders";
 
-        if (_currentSyncFolder
-            && _currentSyncFolder->accountState() == accountState) {
-            _currentSyncFolder->slotTerminateSync();
+        foreach (Folder *f, _folderMap.values()) {
+            if (f
+                && f->isSyncRunning()
+                && f->accountState() == accountState) {
+                f->slotTerminateSync();
+            }
         }
 
         QMutableListIterator<Folder *> it(_scheduledFolders);
@@ -734,7 +724,7 @@ void FolderMan::startScheduledSyncSoon()
     if (_scheduledFolders.empty()) {
         return;
     }
-    if (_currentSyncFolder) {
+    if (isAnySyncRunning()) {
         return;
     }
 
@@ -772,8 +762,11 @@ void FolderMan::startScheduledSyncSoon()
   */
 void FolderMan::slotStartScheduledFolderSync()
 {
-    if (_currentSyncFolder) {
-        qCInfo(lcFolderMan) << "Currently folder " << _currentSyncFolder->remoteUrl().toString() << " is running, wait for finish!";
+    if (isAnySyncRunning()) {
+        for (auto f : _folderMap) {
+            if (f->isSyncRunning())
+                qCInfo(lcFolderMan) << "Currently folder " << f->remoteUrl().toString() << " is running, wait for finish!";
+        }
         return;
     }
 
@@ -820,7 +813,7 @@ void FolderMan::slotEtagPollTimerTimeout()
         if (!f) {
             continue;
         }
-        if (_currentSyncFolder == f) {
+        if (f->isSyncRunning()) {
             continue;
         }
         if (_scheduledFolders.contains(f)) {
@@ -931,12 +924,29 @@ void FolderMan::slotScheduleFolderByTime()
     }
 }
 
+bool FolderMan::isAnySyncRunning() const
+{
+    if (_currentSyncFolder)
+        return true;
+
+    for (auto f : _folderMap) {
+        if (f->isSyncRunning())
+            return true;
+    }
+    return false;
+}
+
 void FolderMan::slotFolderSyncStarted()
 {
+    auto f = qobject_cast<Folder *>(sender());
+    ASSERT(f);
+    if (!f)
+        return;
+
     qCInfo(lcFolderMan, ">========== Sync started for folder [%s] of account [%s] with remote [%s]",
-        qPrintable(_currentSyncFolder->shortGuiLocalPath()),
-        qPrintable(_currentSyncFolder->accountState()->account()->displayName()),
-        qPrintable(_currentSyncFolder->remoteUrl().toString()));
+        qPrintable(f->shortGuiLocalPath()),
+        qPrintable(f->accountState()->account()->displayName()),
+        qPrintable(f->remoteUrl().toString()));
 }
 
 /*
@@ -947,15 +957,22 @@ void FolderMan::slotFolderSyncStarted()
   */
 void FolderMan::slotFolderSyncFinished(const SyncResult &)
 {
-    qCInfo(lcFolderMan, "<========== Sync finished for folder [%s] of account [%s] with remote [%s]",
-        qPrintable(_currentSyncFolder->shortGuiLocalPath()),
-        qPrintable(_currentSyncFolder->accountState()->account()->displayName()),
-        qPrintable(_currentSyncFolder->remoteUrl().toString()));
+    auto f = qobject_cast<Folder *>(sender());
+    ASSERT(f);
+    if (!f)
+        return;
 
-    _lastSyncFolder = _currentSyncFolder;
-    _currentSyncFolder = nullptr;
+    qCInfo(lcFolderMan, "<========== Sync finished for folder [%s] of account [%s] with remote [%s]",
+        qPrintable(f->shortGuiLocalPath()),
+        qPrintable(f->accountState()->account()->displayName()),
+        qPrintable(f->remoteUrl().toString()));
 
-    startScheduledSyncSoon();
+    if (f == _currentSyncFolder) {
+        _lastSyncFolder = _currentSyncFolder;
+        _currentSyncFolder = nullptr;
+    }
+    if (!isAnySyncRunning())
+        startScheduledSyncSoon();
 }
 
 Folder *FolderMan::addFolder(AccountState *accountState, const FolderDefinition &folderDefinition)
@@ -1074,10 +1091,10 @@ void FolderMan::removeFolder(Folder *f)
 
     qCInfo(lcFolderMan) << "Removing " << f->alias();
 
-    const bool currentlyRunning = (_currentSyncFolder == f);
+    const bool currentlyRunning = f->isSyncRunning();
     if (currentlyRunning) {
         // abort the sync now
-        terminateSyncProcess();
+        f->slotTerminateSync();
     }
 
     if (_scheduledFolders.removeAll(f) > 0) {
@@ -1202,7 +1219,7 @@ void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
         const bool currentlyRunning = (_currentSyncFolder == f);
         if (currentlyRunning) {
             // abort the sync now
-            terminateSyncProcess();
+            _currentSyncFolder->slotTerminateSync();
         }
 
         if (_scheduledFolders.removeAll(f) > 0) {
index 057edd625e8bc5340ba676982cc6def3c7385c43..e083d158f4d1b778635900897fe99b9c431fd6c8 100644 (file)
@@ -164,9 +164,22 @@ public:
 
     /**
      * Access to the currently syncing folder.
+     *
+     * Note: This is only the folder that's currently syncing *as-scheduled*. There
+     * may be externally-managed syncs such as from placeholder hydrations.
+     *
+     * See also isAnySyncRunning()
      */
     Folder *currentSyncFolder() const;
 
+    /**
+     * Returns true if any folder is currently syncing.
+     *
+     * This might be a FolderMan-scheduled sync, or a externally
+     * managed sync like a placeholder hydration.
+     */
+    bool isAnySyncRunning() const;
+
     /** Removes all folders */
     int unloadAndDeleteAllFolders();
 
@@ -188,13 +201,6 @@ public:
     void setDirtyProxy();
     void setDirtyNetworkLimits();
 
-    /**
-     * Terminates the current folder sync.
-     *
-     * It does not switch the folder to paused state.
-     */
-    void terminateSyncProcess();
-
 signals:
     /**
       * signal to indicate a folder has changed its sync state.
index 73d68fc9647514e785d88e993847c18ae13040d2..dff804e3aa8fc21635244893e84d5ee0ee3a9cd6 100644 (file)
@@ -1090,9 +1090,9 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
     } else if (state == SyncResult::NotYetStarted) {
         FolderMan *folderMan = FolderMan::instance();
         int pos = folderMan->scheduleQueue().indexOf(f);
-        if (folderMan->currentSyncFolder()
-            && folderMan->currentSyncFolder() != f) {
-            pos += 1;
+        for (auto other : folderMan->map()) {
+            if (other != f && other->isSyncRunning())
+                pos += 1;
         }
         QString message;
         if (pos <= 0) {
index 0fd1abf4baa8b1ac623b2782531b93cfc050fe25..aec990e79ba86a4fe68c61b7a464c5117f88c678 100644 (file)
@@ -245,7 +245,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
         // FIXME: So this doesn't do anything? Needs to be revisited
         Q_UNUSED(text)
         // Don't overwrite the status if we're currently syncing
-        if (FolderMan::instance()->currentSyncFolder())
+        if (FolderMan::instance()->isAnySyncRunning())
             return;
         //_actionStatus->setText(text);
     };