Skip to content

Commit 3a39b44

Browse files
committed
feat: schedule database maintenance in the background (fixes #322)
Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
1 parent b85db1c commit 3a39b44

File tree

11 files changed

+558
-116
lines changed

11 files changed

+558
-116
lines changed

Localizable.xcstrings

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13406,6 +13406,98 @@
1340613406
}
1340713407
}
1340813408
},
13409+
"Every once in a while, Synctrain needs to clean up its internal database. No database maintenance has been performed yet. Tap the above button to start maintenance now." : {
13410+
"localizations" : {
13411+
"de" : {
13412+
"stringUnit" : {
13413+
"state" : "translated",
13414+
"value" : "Hin und wieder muss Synctrain seine interne Datenbank bereinigen. Bisher wurde keine Datenbankwartung durchgeführt. Tippen Sie auf die obige Schaltfläche, um die Wartung jetzt zu starten."
13415+
}
13416+
},
13417+
"es" : {
13418+
"stringUnit" : {
13419+
"state" : "translated",
13420+
"value" : "De vez en cuando, Synctrain necesita limpiar su base de datos interna. Aún no se ha realizado mantenimiento de base de datos. Toca el botón de arriba para iniciar el mantenimiento ahora."
13421+
}
13422+
},
13423+
"it" : {
13424+
"stringUnit" : {
13425+
"state" : "translated",
13426+
"value" : "Di tanto in tanto, Synctrain deve ripulire il suo database interno. Non è stata ancora effettuata alcuna manutenzione del database. Tocca il pulsante sopra per avviare la manutenzione ora."
13427+
}
13428+
},
13429+
"ja" : {
13430+
"stringUnit" : {
13431+
"state" : "translated",
13432+
"value" : "時々、Synctrainは内部データベースをクリーンアップする必要があります。まだデータベースメンテナンスは実施されていません。今すぐメンテナンスを始めるには、上のボタンをタップしてください。"
13433+
}
13434+
},
13435+
"nl" : {
13436+
"stringUnit" : {
13437+
"state" : "translated",
13438+
"value" : "Af en toe moet Synctrain zijn interne database opschonen. Er is nog geen database-onderhoud uitgevoerd. Tik op de bovenstaande knop om het onderhoud nu te starten."
13439+
}
13440+
},
13441+
"uk" : {
13442+
"stringUnit" : {
13443+
"state" : "translated",
13444+
"value" : "Час від часу Synctrain потрібно очистити свою внутрішню базу даних. Ще не виконувалося жодного обслуговування бази даних. Натисніть вищевказану кнопку, щоб розпочати обслуговування зараз."
13445+
}
13446+
},
13447+
"zh-Hans" : {
13448+
"stringUnit" : {
13449+
"state" : "translated",
13450+
"value" : "偶尔,Synctrain 需要清理其内部数据库。尚未进行任何数据库维护。请点击上方按钮立即开始维护。"
13451+
}
13452+
}
13453+
}
13454+
},
13455+
"Every once in a while, Synctrain needs to clean up its internal database. The last database maintenance was performed at %@. Tap the above button to start maintenance now." : {
13456+
"localizations" : {
13457+
"de" : {
13458+
"stringUnit" : {
13459+
"state" : "translated",
13460+
"value" : "Von Zeit zu Zeit muss Synctrain seine interne Datenbank bereinigen. Die letzte Datenbankwartung wurde am %@ durchgeführt. Tippen Sie auf die obige Schaltfläche, um die Wartung jetzt zu starten."
13461+
}
13462+
},
13463+
"es" : {
13464+
"stringUnit" : {
13465+
"state" : "translated",
13466+
"value" : "De vez en cuando, Synctrain necesita limpiar su base de datos interna. El último mantenimiento de la base de datos se realizó el %@. Toca el botón de arriba para iniciar el mantenimiento ahora."
13467+
}
13468+
},
13469+
"it" : {
13470+
"stringUnit" : {
13471+
"state" : "translated",
13472+
"value" : "Ogni tanto Synctrain deve pulire il suo database interno. L'ultima manutenzione del database è stata effettuata il %@. Tocca il pulsante sopra per avviare la manutenzione ora."
13473+
}
13474+
},
13475+
"ja" : {
13476+
"stringUnit" : {
13477+
"state" : "translated",
13478+
"value" : "時々、Synctrainは内部データベースをクリーンアップする必要があります。最後のデータベースメンテナンスは%@に実施されました。今すぐメンテナンスを開始するには、上のボタンをタップしてください。"
13479+
}
13480+
},
13481+
"nl" : {
13482+
"stringUnit" : {
13483+
"state" : "translated",
13484+
"value" : "Af en toe moet Synctrain zijn interne database opschonen. Het laatste database-onderhoud vond plaats op %@. Tik op de bovenstaande knop om nu het onderhoud te starten."
13485+
}
13486+
},
13487+
"uk" : {
13488+
"stringUnit" : {
13489+
"state" : "translated",
13490+
"value" : "Час від часу Synctrain має чистити свою внутрішню базу даних. Останнє обслуговування бази даних було виконано %@. Натисніть на кнопку вище, щоб розпочати обслуговування зараз."
13491+
}
13492+
},
13493+
"zh-Hans" : {
13494+
"stringUnit" : {
13495+
"state" : "translated",
13496+
"value" : "每隔一段时间,Synctrain 需要清理其内部数据库。上次数据库维护是在 %@ 进行的。点击上面的按钮立即开始维护。"
13497+
}
13498+
}
13499+
}
13500+
},
1340913501
"Example file location in folder: " : {
1341013502
"localizations" : {
1341113503
"de" : {
@@ -20256,6 +20348,52 @@
2025620348
}
2025720349
}
2025820350
},
20351+
"Last maintenance" : {
20352+
"localizations" : {
20353+
"de" : {
20354+
"stringUnit" : {
20355+
"state" : "translated",
20356+
"value" : "Letzte Wartung"
20357+
}
20358+
},
20359+
"es" : {
20360+
"stringUnit" : {
20361+
"state" : "translated",
20362+
"value" : "Último mantenimiento"
20363+
}
20364+
},
20365+
"it" : {
20366+
"stringUnit" : {
20367+
"state" : "translated",
20368+
"value" : "Ultima manutenzione"
20369+
}
20370+
},
20371+
"ja" : {
20372+
"stringUnit" : {
20373+
"state" : "translated",
20374+
"value" : "最終メンテナンス"
20375+
}
20376+
},
20377+
"nl" : {
20378+
"stringUnit" : {
20379+
"state" : "translated",
20380+
"value" : "Laatste onderhoud"
20381+
}
20382+
},
20383+
"uk" : {
20384+
"stringUnit" : {
20385+
"state" : "translated",
20386+
"value" : "Останнє обслуговування"
20387+
}
20388+
},
20389+
"zh-Hans" : {
20390+
"stringUnit" : {
20391+
"state" : "translated",
20392+
"value" : "上次维护"
20393+
}
20394+
}
20395+
}
20396+
},
2025920397
"Last modified" : {
2026020398
"localizations" : {
2026120399
"de" : {
@@ -24396,6 +24534,144 @@
2439624534
}
2439724535
}
2439824536
},
24537+
"Perform database maintenance" : {
24538+
"localizations" : {
24539+
"de" : {
24540+
"stringUnit" : {
24541+
"state" : "translated",
24542+
"value" : "Datenbankwartung durchführen"
24543+
}
24544+
},
24545+
"es" : {
24546+
"stringUnit" : {
24547+
"state" : "translated",
24548+
"value" : "Realizar mantenimiento de base de datos"
24549+
}
24550+
},
24551+
"it" : {
24552+
"stringUnit" : {
24553+
"state" : "translated",
24554+
"value" : "Esegui manutenzione del database"
24555+
}
24556+
},
24557+
"ja" : {
24558+
"stringUnit" : {
24559+
"state" : "translated",
24560+
"value" : "データベースのメンテナンスを実行する"
24561+
}
24562+
},
24563+
"nl" : {
24564+
"stringUnit" : {
24565+
"state" : "translated",
24566+
"value" : "Voer database-onderhoud uit"
24567+
}
24568+
},
24569+
"uk" : {
24570+
"stringUnit" : {
24571+
"state" : "translated",
24572+
"value" : "Виконати обслуговування бази даних"
24573+
}
24574+
},
24575+
"zh-Hans" : {
24576+
"stringUnit" : {
24577+
"state" : "translated",
24578+
"value" : "执行数据库维护"
24579+
}
24580+
}
24581+
}
24582+
},
24583+
"Perform database maintenance now" : {
24584+
"localizations" : {
24585+
"de" : {
24586+
"stringUnit" : {
24587+
"state" : "translated",
24588+
"value" : "Datenbankwartung jetzt durchführen"
24589+
}
24590+
},
24591+
"es" : {
24592+
"stringUnit" : {
24593+
"state" : "translated",
24594+
"value" : "Realizar mantenimiento de la base de datos ahora"
24595+
}
24596+
},
24597+
"it" : {
24598+
"stringUnit" : {
24599+
"state" : "translated",
24600+
"value" : "Esegui ora la manutenzione del database"
24601+
}
24602+
},
24603+
"ja" : {
24604+
"stringUnit" : {
24605+
"state" : "translated",
24606+
"value" : "データベースのメンテナンスを今すぐ実行"
24607+
}
24608+
},
24609+
"nl" : {
24610+
"stringUnit" : {
24611+
"state" : "translated",
24612+
"value" : "Onderhoud database nu uitvoeren"
24613+
}
24614+
},
24615+
"uk" : {
24616+
"stringUnit" : {
24617+
"state" : "translated",
24618+
"value" : "Виконати обслуговування бази даних зараз"
24619+
}
24620+
},
24621+
"zh-Hans" : {
24622+
"stringUnit" : {
24623+
"state" : "translated",
24624+
"value" : "立即执行数据库维护"
24625+
}
24626+
}
24627+
}
24628+
},
24629+
"Performing database maintenance..." : {
24630+
"localizations" : {
24631+
"de" : {
24632+
"stringUnit" : {
24633+
"state" : "translated",
24634+
"value" : "Datenbankwartung wird durchgeführt..."
24635+
}
24636+
},
24637+
"es" : {
24638+
"stringUnit" : {
24639+
"state" : "translated",
24640+
"value" : "Realizando mantenimiento de la base de datos..."
24641+
}
24642+
},
24643+
"it" : {
24644+
"stringUnit" : {
24645+
"state" : "translated",
24646+
"value" : "Manutenzione del database in corso..."
24647+
}
24648+
},
24649+
"ja" : {
24650+
"stringUnit" : {
24651+
"state" : "translated",
24652+
"value" : "データベースのメンテナンスを実行中..."
24653+
}
24654+
},
24655+
"nl" : {
24656+
"stringUnit" : {
24657+
"state" : "translated",
24658+
"value" : "Database-onderhoud wordt uitgevoerd..."
24659+
}
24660+
},
24661+
"uk" : {
24662+
"stringUnit" : {
24663+
"state" : "translated",
24664+
"value" : "Виконується обслуговування бази даних..."
24665+
}
24666+
},
24667+
"zh-Hans" : {
24668+
"stringUnit" : {
24669+
"state" : "translated",
24670+
"value" : "正在进行数据库维护..."
24671+
}
24672+
}
24673+
}
24674+
},
2439924675
"Photo back-up" : {
2440024676
"localizations" : {
2440124677
"de" : {

Sushitrain.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
6551053A2D7CB0A700F96814 /* BrowserTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 655105392D7CB0A300F96814 /* BrowserTableView.swift */; };
2828
6551053C2D7D8F8E00F96814 /* BrowserListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6551053B2D7D8F8A00F96814 /* BrowserListView.swift */; };
2929
656802662F13A59000C9FA5D /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656802652F13A58E00C9FA5D /* ToastView.swift */; };
30+
656802682F389C9C00C9FA5D /* MaintenanceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 656802672F389C9800C9FA5D /* MaintenanceManager.swift */; };
3031
6575B3DF2C6012480057686E /* ChangesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6575B3DE2C6012480057686E /* ChangesView.swift */; };
3132
657603EF2D0457B400B36D78 /* Intents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657603EE2D0457B300B36D78 /* Intents.swift */; };
3233
657603F12D045D0B00B36D78 /* QuickActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 657603F02D045D0900B36D78 /* QuickActions.swift */; };
@@ -117,6 +118,7 @@
117118
655105392D7CB0A300F96814 /* BrowserTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserTableView.swift; sourceTree = "<group>"; };
118119
6551053B2D7D8F8A00F96814 /* BrowserListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserListView.swift; sourceTree = "<group>"; };
119120
656802652F13A58E00C9FA5D /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; };
121+
656802672F389C9800C9FA5D /* MaintenanceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaintenanceManager.swift; sourceTree = "<group>"; };
120122
6575B3DE2C6012480057686E /* ChangesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangesView.swift; sourceTree = "<group>"; };
121123
657603EE2D0457B300B36D78 /* Intents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Intents.swift; sourceTree = "<group>"; };
122124
657603F02D045D0900B36D78 /* QuickActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickActions.swift; sourceTree = "<group>"; };
@@ -202,6 +204,7 @@
202204
65AE11FB2C39EE0E00E721D4 /* Sushitrain */ = {
203205
isa = PBXGroup;
204206
children = (
207+
656802672F389C9800C9FA5D /* MaintenanceManager.swift */,
205208
65BBF8442C4BFB9300EC59C4 /* AboutView.swift */,
206209
65AE12662C3B04A100E721D4 /* AddDeviceView.swift */,
207210
65AE126E2C3B14CC00E721D4 /* AddFolderView.swift */,
@@ -398,6 +401,7 @@
398401
65F825EC2CAF1E0900564F57 /* AddressesView.swift in Sources */,
399402
65C9E14C2C3F341F00EDCE6C /* StartView.swift in Sources */,
400403
65F15C012CA06B2300E13DDD /* UploadsView.swift in Sources */,
404+
656802682F389C9C00C9FA5D /* MaintenanceManager.swift in Sources */,
401405
6586863D2CE892130023B1DA /* IgnoresView.swift in Sources */,
402406
65AF4C092D4FA46900A77899 /* ExternalSharing.swift in Sources */,
403407
65BBF8452C4BFB9300EC59C4 /* AboutView.swift in Sources */,

Sushitrain/AppState.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ class SushitrainDelegate: NSObject {
125125
// The action to perform when a user clicks a folder in the dock menu
126126
@AppStorage("menuFolderAction") var menuFolderAction: MenuFolderAction = .finderExceptSelective
127127
#endif
128+
129+
// First run time
130+
@AppStorage("firstRunAt") var firstRunAt: Double = 0.0
128131
}
129132

130133
struct SyncState {
@@ -168,6 +171,7 @@ struct SyncState {
168171
private(set) var isMigratedToNewDatabase: Bool = false
169172
private(set) var syncState: SyncState = SyncState(isDownloading: false, isUploading: false, connectedPeerCount: 0)
170173
private(set) var launchedAt = Date.now
174+
private(set) var maintenanceManager: MaintenanceManager!
171175

172176
fileprivate(set) var discoveredDevices: [String: [String]] = [:]
173177
fileprivate(set) var resolvedListenAddresses = Set<String>()
@@ -202,6 +206,8 @@ struct SyncState {
202206
self.lingerManager = LingerManager(appState: self)
203207
#endif
204208

209+
self.maintenanceManager = MaintenanceManager(appState: self)
210+
205211
self.changeCancellable = self.changePublisher.throttle(
206212
for: .seconds(0.5), scheduler: RunLoop.main, latest: true
207213
).sink { [weak self] _ in
@@ -365,6 +371,10 @@ struct SyncState {
365371
self.startNetworkMonitor()
366372
self.startupState = .started
367373
Log.info("Ready to go")
374+
375+
#if os(macOS)
376+
self.maintenanceManager.scheduleDatabaseMaintenance()
377+
#endif
368378
}
369379
catch let error {
370380
Log.warn("Could not start: \(error.localizedDescription)")
@@ -588,6 +598,10 @@ struct SyncState {
588598
let currentBuild = Int(Bundle.main.buildVersionNumber ?? "0") ?? 0
589599
Log.info("Migrations: current build is \(currentBuild), last run build \(lastRunBuild)")
590600

601+
if self.userSettings.firstRunAt <= 0.0 {
602+
self.userSettings.firstRunAt = Date.timeIntervalSinceReferenceDate
603+
}
604+
591605
if lastRunBuild < currentBuild {
592606
#if os(macOS)
593607
// From build 19 onwards, enable fs watching for all folders by default. It can later be disabled

Sushitrain/BackgroundManager.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,16 @@ enum ContinuedTaskType {
349349
return
350350
}
351351

352+
// Perform database maintenance, if necessary
353+
if self.appState.maintenanceManager.isDatabaseMaintenanceRequired(warning: false) {
354+
do {
355+
try await self.appState.maintenanceManager.performDatabaseMaintenance()
356+
}
357+
catch {
358+
Log.warn("Database maintenance failed: \(error)")
359+
}
360+
}
361+
352362
// Feed the watchdog
353363
Log.info("Rescheduling watchdog")
354364
await self.rescheduleWatchdogNotification()

0 commit comments

Comments
 (0)