diff --git a/Sources/App/CapServer.swift b/Sources/App/CapServer.swift index 67df1c6..23efa5e 100644 --- a/Sources/App/CapServer.swift +++ b/Sources/App/CapServer.swift @@ -14,17 +14,24 @@ final class CapServer { // MARK: Caps - private var saveImmediatelly = true - private var writers: Set + /** + The time to wait for changes to be written to disk. + + This delay is used to prevent file writes for each small update to the caps. + */ + private let saveDelay: TimeInterval = 1 + + /** + The time when a save should occur. + + No save is necessary if this property is `nil`. + */ + private var nextSaveTime: Date? + private var caps = [Int: Cap]() { - didSet { - guard saveImmediatelly else { - return - } - try? saveCaps() - } + didSet { scheduleSave() } } var nextClassifierVersion: Int { @@ -54,6 +61,31 @@ final class CapServer { log("\(caps.count) caps loaded") } + private func scheduleSave() { + nextSaveTime = Date().addingTimeInterval(saveDelay) + DispatchQueue.main.asyncAfter(deadline: .now() + saveDelay) { + self.performScheduledSave() + } + } + + private func performScheduledSave() { + guard let date = nextSaveTime else { + // No save necessary, or already saved + return + } + guard date < Date() else { + // Save pushed to future + return + } + do { + try saveCaps() + nextSaveTime = nil + } catch { + // Attempt save again + scheduleSave() + } + } + private func saveCaps() throws { let data = try JSONEncoder().encode(caps.values.sorted()) try data.write(to: dbFile) @@ -83,14 +115,11 @@ final class CapServer { // MARK: Counts private func updateCounts() throws { - saveImmediatelly = false caps = try caps.mapValues { var cap = $0 cap.count = try count(of: $0.id) return cap } - saveImmediatelly = true - try? saveCaps() } func countImages(in folder: URL) throws -> Int {