Perform slow metadata to FileProviderItem conversion concurrently in FileProviderEnumerator

Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
This commit is contained in:
Claudio Cambra 2023-03-18 21:35:12 +01:00
parent 808f976ae9
commit fe7ca12d9c
No known key found for this signature in database
GPG key ID: C839200C384636B0

View file

@ -273,25 +273,36 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
// MARK: - Helper methods // MARK: - Helper methods
private static func metadatasToFileProviderItems(_ itemMetadatas: [NextcloudItemMetadataTable], ncKit: NextcloudKit) -> [NSFileProviderItem] { private static func metadatasToFileProviderItems(_ itemMetadatas: [NextcloudItemMetadataTable], ncKit: NextcloudKit, completionHandler: @escaping(_ items: [NSFileProviderItem]) -> Void) {
var items: [NSFileProviderItem] = [] var items: [NSFileProviderItem] = []
for itemMetadata in itemMetadatas { let dispatchGroup = DispatchGroup()
if itemMetadata.e2eEncrypted {
Logger.enumeration.info("Skipping encrypted metadata in enumeration: \(itemMetadata.ocId) \(itemMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
continue
}
if let parentItemIdentifier = NextcloudFilesDatabaseManager.shared.parentItemIdentifierFromMetadata(itemMetadata) { for itemMetadata in itemMetadatas {
let item = FileProviderItem(metadata: itemMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: ncKit) dispatchGroup.enter()
Logger.enumeration.debug("Will enumerate item with ocId: \(itemMetadata.ocId) and name: \(itemMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
items.append(item) DispatchQueue.global(qos: .userInitiated).async {
} else { if itemMetadata.e2eEncrypted {
Logger.enumeration.error("Could not get valid parentItemIdentifier for item with ocId: \(itemMetadata.ocId, privacy: .public) and name: \(itemMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash)), skipping enumeration") Logger.enumeration.info("Skipping encrypted metadata in enumeration: \(itemMetadata.ocId, privacy: .public) \(itemMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
dispatchGroup.leave()
return
}
if let parentItemIdentifier = NextcloudFilesDatabaseManager.shared.parentItemIdentifierFromMetadata(itemMetadata) {
let item = FileProviderItem(metadata: itemMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: ncKit)
Logger.enumeration.debug("Will enumerate item with ocId: \(itemMetadata.ocId, privacy: .public) and name: \(itemMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))")
items.append(item)
} else {
Logger.enumeration.error("Could not get valid parentItemIdentifier for item with ocId: \(itemMetadata.ocId, privacy: .public) and name: \(itemMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash)), skipping enumeration")
}
dispatchGroup.leave()
} }
} }
return items dispatchGroup.notify(queue: DispatchQueue.main) {
completionHandler(items)
}
} }
private static func fileProviderPageforNumPage(_ numPage: Int) -> NSFileProviderPage { private static func fileProviderPageforNumPage(_ numPage: Int) -> NSFileProviderPage {
@ -300,21 +311,22 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
private static func completeEnumerationObserver(_ observer: NSFileProviderEnumerationObserver, ncKit: NextcloudKit, numPage: Int, itemMetadatas: [NextcloudItemMetadataTable]) { private static func completeEnumerationObserver(_ observer: NSFileProviderEnumerationObserver, ncKit: NextcloudKit, numPage: Int, itemMetadatas: [NextcloudItemMetadataTable]) {
let items = FileProviderEnumerator.metadatasToFileProviderItems(itemMetadatas, ncKit: ncKit) metadatasToFileProviderItems(itemMetadatas, ncKit: ncKit) { items in
observer.didEnumerate(items) observer.didEnumerate(items)
Logger.enumeration.info("Did enumerate \(items.count) items") Logger.enumeration.info("Did enumerate \(items.count) items")
// TODO: Handle paging properly // TODO: Handle paging properly
/* /*
if items.count == maxItemsPerFileProviderPage { if items.count == maxItemsPerFileProviderPage {
let nextPage = numPage + 1 let nextPage = numPage + 1
let providerPage = NSFileProviderPage("\(nextPage)".data(using: .utf8)!) let providerPage = NSFileProviderPage("\(nextPage)".data(using: .utf8)!)
observer.finishEnumerating(upTo: providerPage) observer.finishEnumerating(upTo: providerPage)
} else { } else {
observer.finishEnumerating(upTo: nil) observer.finishEnumerating(upTo: nil)
}
*/
observer.finishEnumerating(upTo: fileProviderPageforNumPage(numPage))
} }
*/
observer.finishEnumerating(upTo: fileProviderPageforNumPage(numPage))
} }
private static func completeChangesObserver(_ observer: NSFileProviderChangeObserver, anchor: NSFileProviderSyncAnchor, ncKit: NextcloudKit, newMetadatas: [NextcloudItemMetadataTable]?, updatedMetadatas: [NextcloudItemMetadataTable]?, deletedMetadatas: [NextcloudItemMetadataTable]?) { private static func completeChangesObserver(_ observer: NSFileProviderChangeObserver, anchor: NSFileProviderSyncAnchor, ncKit: NextcloudKit, newMetadatas: [NextcloudItemMetadataTable]?, updatedMetadatas: [NextcloudItemMetadataTable]?, deletedMetadatas: [NextcloudItemMetadataTable]?) {
@ -341,36 +353,19 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
allDeletedMetadatas = deletedMetadatas allDeletedMetadatas = deletedMetadatas
} }
var allFpItemUpdates: [FileProviderItem] = []
var allFpItemDeletionsIdentifiers = Array(allDeletedMetadatas.map { NSFileProviderItemIdentifier($0.ocId) }) var allFpItemDeletionsIdentifiers = Array(allDeletedMetadatas.map { NSFileProviderItemIdentifier($0.ocId) })
for updMetadata in allUpdatedMetadatas {
guard let parentItemIdentifier = NextcloudFilesDatabaseManager.shared.parentItemIdentifierFromMetadata(updMetadata) else {
Logger.enumeration.warning("Not enumerating change for metadata: \(updMetadata.ocId) \(updMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash)) as could not get parent item metadata.")
continue
}
guard !updMetadata.e2eEncrypted else {
// Precaution, if all goes well in NKFile conversion then this should not happen
// TODO: Remove when E2EE supported
Logger.enumeration.info("Encrypted metadata in changes enumeration \(updMetadata.ocId) \(updMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash)), adding to deletions")
allFpItemDeletionsIdentifiers.append(NSFileProviderItemIdentifier(updMetadata.ocId))
continue
}
let fpItem = FileProviderItem(metadata: updMetadata, parentItemIdentifier: parentItemIdentifier, ncKit: ncKit)
allFpItemUpdates.append(fpItem)
}
if !allFpItemUpdates.isEmpty {
observer.didUpdate(allFpItemUpdates)
}
if !allFpItemDeletionsIdentifiers.isEmpty { if !allFpItemDeletionsIdentifiers.isEmpty {
observer.didDeleteItems(withIdentifiers: allFpItemDeletionsIdentifiers) observer.didDeleteItems(withIdentifiers: allFpItemDeletionsIdentifiers)
} }
Logger.enumeration.info("Processed \(allUpdatedMetadatas.count) new or updated metadatas, \(allDeletedMetadatas.count) deleted metadatas.") metadatasToFileProviderItems(allUpdatedMetadatas, ncKit: ncKit) { updatedItems in
observer.finishEnumeratingChanges(upTo: anchor, moreComing: false)
if !updatedItems.isEmpty {
observer.didUpdate(updatedItems)
}
Logger.enumeration.info("Processed \(updatedItems.count) new or updated metadatas, \(allDeletedMetadatas.count) deleted metadatas.")
observer.finishEnumeratingChanges(upTo: anchor, moreComing: false)
}
} }
} }