Add option to do a fast enumeration of changes which ignores new, unexplored folders

Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
This commit is contained in:
Claudio Cambra 2024-01-31 16:35:40 +08:00
parent eb86b9141b
commit 179a368f9f
3 changed files with 42 additions and 13 deletions

View file

@ -196,16 +196,22 @@ extension FileProviderEnumerator {
dispatchGroup.wait()
guard criticalError == nil else {
Logger.enumeration.error(
"Received critical error stopping further scanning: \(criticalError!.errorDescription, privacy: .public)"
)
return ([], [], [], [], error: criticalError)
}
var childDirectoriesToScan: [NextcloudItemMetadataTable] = []
var candidateMetadatas: [NextcloudItemMetadataTable] =
if scanChangesOnly {
allUpdatedMetadatas + allNewMetadatas
} else {
allMetadatas
}
var candidateMetadatas: [NextcloudItemMetadataTable]
if scanChangesOnly, fastEnumeration {
candidateMetadatas = allUpdatedMetadatas
} else if scanChangesOnly {
candidateMetadatas = allUpdatedMetadatas + allNewMetadatas
} else {
candidateMetadatas = allMetadatas
}
for candidateMetadata in candidateMetadatas {
if candidateMetadata.directory {
@ -213,6 +219,8 @@ extension FileProviderEnumerator {
}
}
Logger.enumeration.debug("Candidate metadatas for further scan: \(candidateMetadatas, privacy: .public)")
if childDirectoriesToScan.isEmpty {
return (
metadatas: allMetadatas, newMetadatas: allNewMetadatas,
@ -221,11 +229,12 @@ extension FileProviderEnumerator {
}
for childDirectory in childDirectoriesToScan {
Logger.enumeration.debug(
"About to recursively scan: \(childDirectory.urlBase, privacy: .public) with etag: \(childDirectory.etag, privacy: .public)"
)
let childScanResult = scanRecursively(
childDirectory,
ncAccount: ncAccount,
ncKit: ncKit,
scanChangesOnly: scanChangesOnly)
childDirectory, ncAccount: ncAccount, ncKit: ncKit, scanChangesOnly: scanChangesOnly
)
allMetadatas += childScanResult.metadatas
allNewMetadatas += childScanResult.newMetadatas

View file

@ -28,21 +28,24 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
private static let maxItemsPerFileProviderPage = 100
let ncAccount: NextcloudAccount
let ncKit: NextcloudKit
let fastEnumeration: Bool
var serverUrl: String = ""
var isInvalidated = false
private static func isSystemIdentifier(_ identifier: NSFileProviderItemIdentifier) -> Bool {
identifier == .rootContainer || identifier == .trashContainer || identifier == .workingSet
}
init(
enumeratedItemIdentifier: NSFileProviderItemIdentifier,
ncAccount: NextcloudAccount,
ncKit: NextcloudKit
ncKit: NextcloudKit,
fastEnumeration: Bool = true
) {
self.enumeratedItemIdentifier = enumeratedItemIdentifier
self.ncAccount = ncAccount
self.ncKit = ncKit
self.fastEnumeration = fastEnumeration
if FileProviderEnumerator.isSystemIdentifier(enumeratedItemIdentifier) {
Logger.enumeration.debug(

View file

@ -51,6 +51,19 @@ import OSLog
return session
}()
// Whether or not we are going to recursively scan new folders when they are discovered.
// Apple's recommendation is that we should always scan the file hierarchy fully.
// This does lead to long load times when a file provider domain is initially configured.
// We can instead do a fast enumeration where we only scan folders as the user navigates through
// them, thereby avoiding this issue; the trade-off is that we will be unable to detect
// materialised file moves to unexplored folders, therefore deleting the item when we could have
// just moved it instead.
//
// Since it's not desirable to cancel a long recursive enumeration half-way through, we do the
// fast enumeration by default. We prompt the user on the client side to run a proper, full
// enumeration if they want for safety.
var fastEnumeration = true
required init(domain: NSFileProviderDomain) {
// The containing application must create a domain using
// `NSFileProviderManager.add(_:, completionHandler:)`. The system will then launch the
@ -787,7 +800,11 @@ import OSLog
}
return FileProviderEnumerator(
enumeratedItemIdentifier: containerItemIdentifier, ncAccount: ncAccount, ncKit: ncKit)
enumeratedItemIdentifier: containerItemIdentifier,
ncAccount: ncAccount,
ncKit: ncKit,
fastEnumeration: fastEnumeration
)
}
func materializedItemsDidChange(completionHandler: @escaping () -> Void) {