From 17fea8845055e196ea682153c187b930ce9e84ae Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Fri, 10 Mar 2023 22:11:05 +0100 Subject: [PATCH] Replace full depth scanning of changes on every enumerate changes request with smarter recursive algorithm Signed-off-by: Claudio Cambra --- .../FileProviderEnumerator.swift | 164 +++++++++++------- 1 file changed, 105 insertions(+), 59 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift index fdced9fa7..49c06a2bc 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift @@ -206,65 +206,14 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { NSLog("Enumerating changes in working set for user: %@ with serverUrl: %@", ncAccount.username, serverUrl) // TODO: Enumerate changes in favourites and other special items - let dbManager = NextcloudFilesDatabaseManager.shared - let directoryMetadatas = dbManager.directoryMetadatas(account: ncAccount.ncKitAccount) - - var allNewMetadatas: [NextcloudItemMetadataTable] = [] - var allUpdatedMetadatas: [NextcloudItemMetadataTable] = [] - var allDeletedMetadatas: [NextcloudItemMetadataTable] = [] - - let dispatchGroup = DispatchGroup() // TODO: Maybe own thread? - - for directoryMetadata in directoryMetadatas { - dispatchGroup.enter() - - FileProviderEnumerator.readServerUrl(directoryMetadata.serverUrl, ncAccount: ncAccount, ncKit: ncKit) { _, newMetadatas, updatedMetadatas, deletedMetadatas, readError in - guard readError == nil else { - NSLog("Finishing enumeration of changes at %@ with error %@", directoryMetadata.serverUrl, readError!.localizedDescription) - - if let nkReadError = readError as? NKError, nkReadError.errorCode == 404 { - NSLog("404 error means item no longer exists. Deleting metadata and reporting as deletion without error") - - guard let directoryItemMetadata = dbManager.itemMetadataFromOcId(directoryMetadata.ocId) else { - NSLog("Can't delete directory properly as item metadata not found...") - dispatchGroup.leave() - return - } - - dbManager.deleteDirectoryAndSubdirectoriesMetadata(ocId: directoryMetadata.ocId) - allDeletedMetadatas.append(directoryItemMetadata) - } - - dispatchGroup.leave() - return - } - - NSLog("Finished reading serverUrl: %@ for user: %@", directoryMetadata.serverUrl, self.ncAccount.ncKitAccount) - if let newMetadatas = newMetadatas { - allNewMetadatas += newMetadatas - } else { - NSLog("WARNING: Nil new metadatas received for reading of changes at %@ for user: %@", directoryMetadata.serverUrl, self.ncAccount.ncKitAccount) - } - - if let updatedMetadatas = updatedMetadatas { - allUpdatedMetadatas += updatedMetadatas - } else { - NSLog("WARNING: Nil updated metadatas received for reading of changes at %@ for user: %@", directoryMetadata.serverUrl, self.ncAccount.ncKitAccount) - } - - if let deletedMetadatas = deletedMetadatas { - allDeletedMetadatas += deletedMetadatas - } else { - NSLog("WARNING: Nil deleted metadatas received for reading of changes at %@ for user: %@", directoryMetadata.serverUrl, self.ncAccount.ncKitAccount) - } - - dispatchGroup.leave() - } - - dispatchGroup.wait() - } - - FileProviderEnumerator.completeChangesObserver(observer, anchor: anchor, ncKit: self.ncKit, newMetadatas: allNewMetadatas, updatedMetadatas: allUpdatedMetadatas, deletedMetadatas: allDeletedMetadatas) + let scanResults = FileProviderEnumerator.fullRecursiveScanForChanges(ncAccount: ncAccount, ncKit: ncKit) + + FileProviderEnumerator.completeChangesObserver(observer, + anchor: anchor, + ncKit: ncKit, + newMetadatas: scanResults.newMetadatas, + updatedMetadatas: scanResults.updatedMetadatas, + deletedMetadatas: scanResults.deletedMetadatas) return } else if enumeratedItemIdentifier == .trashContainer { NSLog("Enumerating changes in trash set for user: %@ with serverUrl: %@", ncAccount.username, serverUrl) @@ -415,6 +364,103 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { observer.finishEnumeratingChanges(upTo: anchor, moreComing: false) } + private static func fullRecursiveScanForChanges(ncAccount: NextcloudAccount, ncKit: NextcloudKit) -> (newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], deletedMetadatas: [NextcloudItemMetadataTable]) { + + let rootContainerDirectoryMetadata = NextcloudDirectoryMetadataTable() + rootContainerDirectoryMetadata.serverUrl = ncAccount.davFilesUrl + rootContainerDirectoryMetadata.account = ncAccount.ncKitAccount + rootContainerDirectoryMetadata.ocId = NSFileProviderItemIdentifier.rootContainer.rawValue + + return scanRecursivelyForChanges(rootContainerDirectoryMetadata, ncAccount: ncAccount, ncKit: ncKit) + } + + private static func scanRecursivelyForChanges(_ directoryMetadata: NextcloudDirectoryMetadataTable, ncAccount: NextcloudAccount, ncKit: NextcloudKit) -> (newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], deletedMetadatas: [NextcloudItemMetadataTable]) { + var allNewMetadatas: [NextcloudItemMetadataTable] = [] + var allUpdatedMetadatas: [NextcloudItemMetadataTable] = [] + var allDeletedMetadatas: [NextcloudItemMetadataTable] = [] + + let dbManager = NextcloudFilesDatabaseManager.shared + let dispatchGroup = DispatchGroup() // TODO: Maybe own thread? + + dispatchGroup.enter() + + NSLog("About to read: %@", directoryMetadata.serverUrl) + FileProviderEnumerator.readServerUrl(directoryMetadata.serverUrl, ncAccount: ncAccount, ncKit: ncKit) { _, newMetadatas, updatedMetadatas, deletedMetadatas, readError in + guard readError == nil else { + NSLog("Finishing enumeration of changes at %@ with error %@", directoryMetadata.serverUrl, readError!.localizedDescription) + + if let nkReadError = readError as? NKError { + if nkReadError.errorCode == 404 { + NSLog("404 error means item no longer exists. Deleting metadata and reporting as deletion without error") + + guard let directoryItemMetadata = dbManager.itemMetadataFromOcId(directoryMetadata.ocId) else { + NSLog("Can't delete directory properly as item metadata not found...") + dispatchGroup.leave() + return + } + + dbManager.deleteDirectoryAndSubdirectoriesMetadata(ocId: directoryMetadata.ocId) + allDeletedMetadatas.append(directoryItemMetadata) + } else if nkReadError.errorCode == -200 { // All is well, just no changed etags + NSLog("Error was to say no changed files. No need to check children.") + } + } + + dispatchGroup.leave() + return + } + + NSLog("Finished reading serverUrl: %@ for user: %@", directoryMetadata.serverUrl, ncAccount.ncKitAccount) + if let newMetadatas = newMetadatas { + allNewMetadatas += newMetadatas + } else { + NSLog("WARNING: Nil new metadatas received for reading of changes at %@ for user: %@", directoryMetadata.serverUrl, ncAccount.ncKitAccount) + } + + if let updatedMetadatas = updatedMetadatas { + allUpdatedMetadatas += updatedMetadatas + } else { + NSLog("WARNING: Nil updated metadatas received for reading of changes at %@ for user: %@", directoryMetadata.serverUrl, ncAccount.ncKitAccount) + } + + if let deletedMetadatas = deletedMetadatas { + allDeletedMetadatas += deletedMetadatas + } else { + NSLog("WARNING: Nil deleted metadatas received for reading of changes at %@ for user: %@", directoryMetadata.serverUrl, ncAccount.ncKitAccount) + } + + dispatchGroup.leave() + } + + dispatchGroup.wait() + + var updatedDirectories: [NextcloudDirectoryMetadataTable] = [] + for updatedMetadata in allUpdatedMetadatas { + if updatedMetadata.directory { + guard let directoryMetadata = dbManager.directoryMetadata(ocId: updatedMetadata.ocId) else { + NSLog("Could not find matching directory metadata for updated item metadata, cannot scan for updates") + continue + } + + updatedDirectories.append(directoryMetadata) + } + } + + if updatedDirectories.isEmpty { + return (newMetadatas: allNewMetadatas, updatedMetadatas: allUpdatedMetadatas, deletedMetadatas: allDeletedMetadatas) + } + + for childDirectory in updatedDirectories { + let childScanResult = scanRecursivelyForChanges(childDirectory, ncAccount: ncAccount, ncKit: ncKit) + + allNewMetadatas += childScanResult.newMetadatas + allUpdatedMetadatas += childScanResult.updatedMetadatas + allDeletedMetadatas += childScanResult.deletedMetadatas + } + + return (newMetadatas: allNewMetadatas, updatedMetadatas: allUpdatedMetadatas, deletedMetadatas: allDeletedMetadatas) + } + private static func readServerUrl(_ serverUrl: String, ncAccount: NextcloudAccount, ncKit: NextcloudKit, fullDepthRead: Bool = false, completionHandler: @escaping (_ metadatas: [NextcloudItemMetadataTable]?, _ newMetadatas: [NextcloudItemMetadataTable]?, _ updatedMetadatas: [NextcloudItemMetadataTable]?, _ deletedMetadatas: [NextcloudItemMetadataTable]?, _ readError: Error?) -> Void) { let dbManager = NextcloudFilesDatabaseManager.shared let ncKitAccount = ncAccount.ncKitAccount -- 2.30.2