Skip to content

Commit 1c7d2c8

Browse files
authored
Merge pull request #105 from nextcloud/feature/async-working-set-change-check
Asynchronously check for changes within remote change observer rather than enumerator, signal changes only when necessary
2 parents 18f674a + 67de21f commit 1c7d2c8

15 files changed

Lines changed: 1153 additions & 401 deletions

Sources/NextcloudFileProviderKit/Database/FilesDatabaseManager+Directories.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ extension FilesDatabaseManager {
9090

9191
let database = ncDatabase()
9292
do {
93-
try database.write { database.delete(directoryMetadata) }
93+
try database.write { directoryMetadata.deleted = true }
9494
} catch let error {
9595
Self.logger.error(
9696
"""
@@ -113,7 +113,7 @@ extension FilesDatabaseManager {
113113
for result in results {
114114
let inactiveItemMetadata = SendableItemMetadata(value: result)
115115
do {
116-
try database.write { database.delete(result) }
116+
try database.write { result.deleted = true }
117117
deletedMetadatas.append(inactiveItemMetadata)
118118
} catch let error {
119119
Self.logger.error(

Sources/NextcloudFileProviderKit/Database/FilesDatabaseManager.swift

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public final class FilesDatabaseManager: Sendable {
234234

235235
for existingMetadata in existingMetadatas {
236236
guard !updatedMetadatas.contains(where: { $0.ocId == existingMetadata.ocId }),
237-
let metadataToDelete = itemMetadatas.where({ $0.ocId == existingMetadata.ocId }).first
237+
var metadataToDelete = itemMetadatas.where({ $0.ocId == existingMetadata.ocId }).first
238238
else { continue }
239239

240240
deletedMetadatas.append(metadataToDelete)
@@ -245,6 +245,7 @@ public final class FilesDatabaseManager: Sendable {
245245
ocID: \(existingMetadata.ocId, privacy: .public)
246246
etag: \(existingMetadata.etag, privacy: .public)
247247
fileName: \(existingMetadata.fileName, privacy: .public)"
248+
syncTime: \(existingMetadata.syncTime, privacy: .public)
248249
"""
249250
)
250251
}
@@ -282,6 +283,7 @@ public final class FilesDatabaseManager: Sendable {
282283
if keepExistingDownloadState {
283284
updatedMetadata.downloaded = existingMetadata.downloaded
284285
}
286+
updatedMetadata.visitedDirectory = existingMetadata.visitedDirectory
285287

286288
returningUpdatedMetadatas.append(updatedMetadata)
287289

@@ -291,6 +293,7 @@ public final class FilesDatabaseManager: Sendable {
291293
ocID: \(updatedMetadata.ocId, privacy: .public)
292294
etag: \(updatedMetadata.etag, privacy: .public)
293295
fileName: \(updatedMetadata.fileName, privacy: .public)
296+
syncTime: \(updatedMetadata.syncTime, privacy: .public)
294297
"""
295298
)
296299
} else {
@@ -300,6 +303,7 @@ public final class FilesDatabaseManager: Sendable {
300303
ocID: \(updatedMetadata.ocId, privacy: .public)
301304
etag: \(updatedMetadata.etag, privacy: .public)
302305
fileName: \(updatedMetadata.fileName, privacy: .public)
306+
syncTime: \(updatedMetadata.syncTime, privacy: .public)
303307
"""
304308
)
305309
}
@@ -313,6 +317,23 @@ public final class FilesDatabaseManager: Sendable {
313317
ocID: \(updatedMetadata.ocId, privacy: .public)
314318
etag: \(updatedMetadata.etag, privacy: .public)
315319
fileName: \(updatedMetadata.fileName, privacy: .public)
320+
parentDirectoryUrl: \(updatedMetadata.serverUrl, privacy: .public)
321+
account: \(updatedMetadata.account, privacy: .public)
322+
content type: \(updatedMetadata.contentType, privacy: .public)
323+
is directory: \(updatedMetadata.directory, privacy: .public)
324+
creation date: \(updatedMetadata.creationDate, privacy: .public)
325+
date: \(updatedMetadata.date, privacy: .public)
326+
lock: \(updatedMetadata.lock, privacy: .public)
327+
lockTimeOut: \(updatedMetadata.lockTimeOut?.description ?? "", privacy: .public)
328+
lockOwner: \(updatedMetadata.lockOwner ?? "", privacy: .public)
329+
permissions: \(updatedMetadata.permissions, privacy: .public)
330+
size: \(updatedMetadata.size, privacy: .public)
331+
trashbinFileName: \(updatedMetadata.trashbinFileName, privacy: .public)
332+
downloaded: \(updatedMetadata.downloaded, privacy: .public)
333+
uploaded: \(updatedMetadata.uploaded, privacy: .public)
334+
visitedDirectory: \(updatedMetadata.visitedDirectory, privacy: .public)
335+
deleted: \(updatedMetadata.deleted, privacy: .public)
336+
syncTime: \(updatedMetadata.syncTime, privacy: .public)
316337
"""
317338
)
318339
}
@@ -368,12 +389,14 @@ public final class FilesDatabaseManager: Sendable {
368389
readTargetMetadata = nil
369390
}
370391

371-
// NOTE: These metadatas are managed -- be careful!
372392
let metadatasToDelete = processItemMetadatasToDelete(
373393
existingMetadatas: existingMetadatas,
374394
updatedMetadatas: updatedChildMetadatas
375-
)
376-
let metadatasToDeleteCopy = metadatasToDelete.map { SendableItemMetadata(value: $0) }
395+
).map {
396+
var metadata = SendableItemMetadata(value: $0)
397+
metadata.deleted = true
398+
return metadata
399+
}
377400

378401
let metadatasToChange = processItemMetadatasToUpdate(
379402
existingMetadatas: existingMetadatas,
@@ -396,32 +419,34 @@ public final class FilesDatabaseManager: Sendable {
396419
}
397420

398421
if var readTargetMetadata {
422+
if readTargetMetadata.directory {
423+
readTargetMetadata.visitedDirectory = true
424+
}
425+
399426
if let existing = itemMetadata(ocId: readTargetMetadata.ocId) {
400427
if existing.status == Status.normal.rawValue,
401428
!existing.isInSameDatabaseStoreableRemoteState(readTargetMetadata)
402429
{
403-
Self.logger.info("Depth 1 read target changed: \(readTargetMetadata.ocId)")
430+
Self.logger.info("Depth 1 read target changed: \(readTargetMetadata.ocId, privacy: .public)")
404431
if keepExistingDownloadState {
405432
readTargetMetadata.downloaded = existing.downloaded
406433
}
407-
if readTargetMetadata.directory {
408-
readTargetMetadata.visitedDirectory = true
409-
}
410434
metadatasToUpdate.insert(readTargetMetadata, at: 0)
411435
}
412436
} else {
413-
Self.logger.info("Depth 1 read target is new: \(readTargetMetadata.ocId)")
437+
Self.logger.info("Depth 1 read target is new: \(readTargetMetadata.ocId, privacy: .public)")
414438
metadatasToCreate.insert(readTargetMetadata, at: 0)
415439
}
416440
}
417441

418442
try database.write {
419-
database.delete(metadatasToDelete)
443+
// Do not delete the metadatas that have been deleted
444+
database.add(metadatasToDelete.map { RealmItemMetadata(value: $0) }, update: .modified)
420445
database.add(metadatasToUpdate.map { RealmItemMetadata(value: $0) }, update: .modified)
421446
database.add(metadatasToCreate.map { RealmItemMetadata(value: $0) }, update: .all)
422447
}
423448

424-
return (metadatasToCreate, metadatasToUpdate, metadatasToDeleteCopy)
449+
return (metadatasToCreate, metadatasToUpdate, metadatasToDelete)
425450
} catch {
426451
Self.logger.error(
427452
"""
@@ -467,6 +492,7 @@ public final class FilesDatabaseManager: Sendable {
467492
ocID: \(metadata.ocId, privacy: .public)
468493
etag: \(metadata.etag, privacy: .public)
469494
fileName: \(metadata.fileName, privacy: .public)
495+
syncTime: \(metadata.syncTime, privacy: .public)
470496
"""
471497
)
472498
}
@@ -513,6 +539,8 @@ public final class FilesDatabaseManager: Sendable {
513539
downloaded: \(metadata.downloaded, privacy: .public)
514540
uploaded: \(metadata.uploaded, privacy: .public)
515541
visitedDirectory: \(metadata.visitedDirectory, privacy: .public)
542+
deleted: \(metadata.deleted, privacy: .public)
543+
syncTime: \(metadata.syncTime, privacy: .public)
516544
"""
517545
)
518546
}
@@ -523,6 +551,7 @@ public final class FilesDatabaseManager: Sendable {
523551
ocID: \(metadata.ocId, privacy: .public)
524552
etag: \(metadata.etag, privacy: .public)
525553
fileName: \(metadata.fileName, privacy: .public)
554+
syncTime: \(metadata.syncTime, privacy: .public)
526555
received error: \(error.localizedDescription, privacy: .public)
527556
"""
528557
)
@@ -535,7 +564,7 @@ public final class FilesDatabaseManager: Sendable {
535564
let database = ncDatabase()
536565
try database.write {
537566
Self.logger.debug("Deleting item metadata. \(ocId, privacy: .public)")
538-
database.delete(results)
567+
results.forEach { $0.deleted = true }
539568
}
540569
return true
541570
} catch {
@@ -614,6 +643,7 @@ public final class FilesDatabaseManager: Sendable {
614643
fileName: \(metadata.fileName, privacy: .public),
615644
serverUrl: \(metadata.serverUrl, privacy: .public),
616645
account: \(metadata.account, privacy: .public),
646+
syncTime: \(metadata.syncTime, privacy: .public)
617647
"""
618648
)
619649
return nil
@@ -652,12 +682,68 @@ public final class FilesDatabaseManager: Sendable {
652682
return NSFileProviderItemIdentifier(parentMetadata.ocId)
653683
}
654684

655-
public func materialisedItemMetadatas(account: String) -> [SendableItemMetadata] {
685+
private func managedMaterialisedItemMetadatas(account: String) -> Results<RealmItemMetadata> {
656686
itemMetadatas
657687
.where {
658688
$0.account == account &&
659689
(($0.directory && $0.visitedDirectory) || (!$0.directory && $0.downloaded))
660690
}
661-
.toUnmanagedResults()
691+
}
692+
693+
public func materialisedItemMetadatas(account: String) -> [SendableItemMetadata] {
694+
managedMaterialisedItemMetadatas(account: account).toUnmanagedResults()
695+
}
696+
697+
public func pendingWorkingSetChanges(
698+
account: Account, since date: Date
699+
) -> (updated: [SendableItemMetadata], deleted: [SendableItemMetadata]) {
700+
let accId = account.ncKitAccount
701+
let pending = managedMaterialisedItemMetadatas(account: accId).where { $0.syncTime > date }
702+
var updated = pending.where { !$0.deleted }.toUnmanagedResults()
703+
var deleted = pending.where { $0.deleted }.toUnmanagedResults()
704+
705+
var handledUpdateOcIds = Set(updated.map(\.ocId))
706+
updated
707+
.map {
708+
var serverUrl = $0.serverUrl + "/" + $0.fileName
709+
if serverUrl.last == "/" { serverUrl.removeLast() }
710+
return serverUrl
711+
}
712+
.forEach { serverUrl in
713+
Self.logger.debug("Checking (updated) \(serverUrl, privacy: .public)")
714+
itemMetadatas
715+
.where { $0.serverUrl == serverUrl && $0.syncTime > date }
716+
.forEach { metadata in
717+
Self.logger.debug("Checking item: \(metadata.fileName, privacy: .public)")
718+
guard !handledUpdateOcIds.contains(metadata.ocId) else { return }
719+
handledUpdateOcIds.insert(metadata.ocId)
720+
let sendableMetadata = SendableItemMetadata(value: metadata)
721+
if metadata.deleted {
722+
deleted.append(sendableMetadata)
723+
} else {
724+
updated.append(sendableMetadata)
725+
}
726+
Self.logger.debug("Appended item: \(metadata.fileName, privacy: .public)")
727+
}
728+
}
729+
730+
var handledDeleteOcIds = Set(deleted.map(\.ocId))
731+
deleted
732+
.map {
733+
var serverUrl = $0.serverUrl + "/" + $0.fileName
734+
if serverUrl.last == "/" { serverUrl.removeLast() }
735+
return serverUrl
736+
}
737+
.forEach { serverUrl in
738+
Self.logger.debug("Checking (deletion) \(serverUrl, privacy: .public)")
739+
itemMetadatas
740+
.where { $0.serverUrl.starts(with: serverUrl) && $0.syncTime > date }
741+
.forEach { metadata in
742+
guard !handledDeleteOcIds.contains(metadata.ocId) else { return }
743+
deleted.append(SendableItemMetadata(value: metadata))
744+
}
745+
}
746+
747+
return (updated, deleted)
662748
}
663749
}

Sources/NextcloudFileProviderKit/Enumeration/Enumerator+SyncEngine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ extension Enumerator {
3535
}
3636
dbManager.addItemMetadata(metadata)
3737
}
38-
let metadatas = files[startIndex..<files.count].map { $0.toItemMetadata() }
38+
let metadatas = files[startIndex...].map { $0.toItemMetadata() }
3939
metadatas.forEach { dbManager.addItemMetadata($0) }
4040
return (metadatas, nil)
4141
}

0 commit comments

Comments
 (0)