Handle invalidation of enumerator during long recursive scans in FileProviderEnumerator
authorClaudio Cambra <claudio.cambra@nextcloud.com>
Sat, 18 Mar 2023 15:05:34 +0000 (16:05 +0100)
committerClaudio Cambra <claudio.cambra@nextcloud.com>
Fri, 12 May 2023 05:29:56 +0000 (13:29 +0800)
Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator+RemoteSync.swift
shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift

index 8dd98ac0f9f8e724ec5f1ebc9ed3b18f49c91834..efc5ba69e95dac6db66146a1cdd7ff8668248c57 100644 (file)
@@ -17,7 +17,7 @@ import NextcloudKit
 import OSLog
 
 extension FileProviderEnumerator {
-    static func fullRecursiveScan(ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool, completionHandler: @escaping(_ metadatas: [NextcloudItemMetadataTable], _ newMetadatas: [NextcloudItemMetadataTable], _ updatedMetadatas: [NextcloudItemMetadataTable], _ deletedMetadatas: [NextcloudItemMetadataTable], _ error: NKError?) -> Void) {
+    func fullRecursiveScan(ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool, completionHandler: @escaping(_ metadatas: [NextcloudItemMetadataTable], _ newMetadatas: [NextcloudItemMetadataTable], _ updatedMetadatas: [NextcloudItemMetadataTable], _ deletedMetadatas: [NextcloudItemMetadataTable], _ error: NKError?) -> Void) {
 
         let rootContainerDirectoryMetadata = NextcloudItemMetadataTable()
         rootContainerDirectoryMetadata.directory = true
@@ -27,7 +27,7 @@ extension FileProviderEnumerator {
         let dispatchQueue = DispatchQueue(label: "recursiveChangeEnumerationQueue", qos: .background)
 
         dispatchQueue.async {
-            let results = scanRecursively(rootContainerDirectoryMetadata, ncAccount: ncAccount, ncKit: ncKit, scanChangesOnly: scanChangesOnly)
+            let results = self.scanRecursively(rootContainerDirectoryMetadata, ncAccount: ncAccount, ncKit: ncKit, scanChangesOnly: scanChangesOnly)
 
             // Run a check to ensure files deleted in one location are not updated in another (e.g. when moved)
             // The recursive scan provides us with updated/deleted metadatas only on a folder by folder basis;
@@ -48,7 +48,11 @@ extension FileProviderEnumerator {
         }
     }
 
-    private static func scanRecursively(_ directoryMetadata: NextcloudItemMetadataTable, ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool) -> (metadatas: [NextcloudItemMetadataTable], newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], deletedMetadatas: [NextcloudItemMetadataTable], error: NKError?) {
+    private func scanRecursively(_ directoryMetadata: NextcloudItemMetadataTable, ncAccount: NextcloudAccount, ncKit: NextcloudKit, scanChangesOnly: Bool) -> (metadatas: [NextcloudItemMetadataTable], newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], deletedMetadatas: [NextcloudItemMetadataTable], error: NKError?) {
+
+        if self.isInvalidated {
+            return ([], [], [], [], nil)
+        }
 
         assert(directoryMetadata.directory, "Can only recursively scan a directory.")
 
index 8068269be501b0ad3afb55ca8dcd9cd3ff1f847a..329a8f57f90ffb48b979a23b7a1cec262a372109 100644 (file)
@@ -28,6 +28,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
     let ncAccount: NextcloudAccount
     let ncKit: NextcloudKit
     var serverUrl: String = ""
+    var isInvalidated = false
 
     private static func isSystemIdentifier(_ identifier: NSFileProviderItemIdentifier) -> Bool {
         return identifier == .rootContainer ||
@@ -60,7 +61,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
     }
 
     func invalidate() {
-        // TODO: perform invalidation of server connection if necessary
+        self.isInvalidated = true
     }
 
     // MARK: - Protocol methods
@@ -243,12 +244,18 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
         if enumeratedItemIdentifier == .workingSet {
             Logger.enumeration.debug("Enumerating changes in working set for user: \(self.ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
 
-            FileProviderEnumerator.fullRecursiveScan(ncAccount: self.ncAccount, ncKit: self.ncKit, scanChangesOnly: true) { _, newMetadatas, updatedMetadatas, deletedMetadatas, error in
+            fullRecursiveScan(ncAccount: self.ncAccount, ncKit: self.ncKit, scanChangesOnly: true) { _, newMetadatas, updatedMetadatas, deletedMetadatas, error in
+
+                if self.isInvalidated {
+                    Logger.enumeration.info("Enumerator invalidated during working set change scan. For user: \(self.ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash))")
+                    observer.finishEnumeratingWithError(NSFileProviderError(.cannotSynchronize))
+                    return
+                }
 
                 guard error == nil else {
                     Logger.enumeration.info("Finished recursive change enumeration of working set for user: \(self.ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash)) with error: \(error!.errorDescription, privacy: .public)")
                     observer.finishEnumeratingWithError(error!.toFileProviderError())
-                    return;
+                    return
                 }
 
                 Logger.enumeration.info("Finished recursive change enumeration of working set for user: \(self.ncAccount.ncKitAccount, privacy: OSLogPrivacy.auto(mask: .hash)). Enumerating items.")