use mutex

This commit is contained in:
Alex 2025-07-05 14:22:59 -05:00
parent 2f5d75ce21
commit f8ab533acb
No known key found for this signature in database
GPG Key ID: 53CD082B3A5E1082
2 changed files with 91 additions and 33 deletions

View File

@ -9,8 +9,57 @@ class BackgroundSyncManager {
Cancelable<void>? _deviceAlbumSyncTask; Cancelable<void>? _deviceAlbumSyncTask;
Cancelable<void>? _hashTask; Cancelable<void>? _hashTask;
Completer<void>? _localSyncMutex;
Completer<void>? _remoteSyncMutex;
Completer<void>? _hashMutex;
BackgroundSyncManager(); BackgroundSyncManager();
Future<T> _withMutex<T>(
Completer<void>? Function() getMutex,
void Function(Completer<void>?) setMutex,
Future<T> Function() operation,
) async {
while (getMutex() != null) {
await getMutex()!.future;
}
final mutex = Completer<void>();
setMutex(mutex);
try {
final result = await operation();
return result;
} finally {
setMutex(null);
mutex.complete();
}
}
Future<T> _withLocalSyncMutex<T>(Future<T> Function() operation) {
return _withMutex(
() => _localSyncMutex,
(mutex) => _localSyncMutex = mutex,
operation,
);
}
Future<T> _withRemoteSyncMutex<T>(Future<T> Function() operation) {
return _withMutex(
() => _remoteSyncMutex,
(mutex) => _remoteSyncMutex = mutex,
operation,
);
}
Future<T> _withHashMutex<T>(Future<T> Function() operation) {
return _withMutex(
() => _hashMutex,
(mutex) => _hashMutex = mutex,
operation,
);
}
Future<void> cancel() { Future<void> cancel() {
final futures = <Future>[]; final futures = <Future>[];
@ -25,6 +74,7 @@ class BackgroundSyncManager {
// No need to cancel the task, as it can also be run when the user logs out // No need to cancel the task, as it can also be run when the user logs out
Future<void> syncLocal({bool full = false}) { Future<void> syncLocal({bool full = false}) {
return _withLocalSyncMutex(() async {
if (_deviceAlbumSyncTask != null) { if (_deviceAlbumSyncTask != null) {
return _deviceAlbumSyncTask!.future; return _deviceAlbumSyncTask!.future;
} }
@ -44,10 +94,12 @@ class BackgroundSyncManager {
return _deviceAlbumSyncTask!.whenComplete(() { return _deviceAlbumSyncTask!.whenComplete(() {
_deviceAlbumSyncTask = null; _deviceAlbumSyncTask = null;
}); });
});
} }
// No need to cancel the task, as it can also be run when the user logs out // No need to cancel the task, as it can also be run when the user logs out
Future<void> hashAssets() { Future<void> hashAssets() {
return _withHashMutex(() async {
if (_hashTask != null) { if (_hashTask != null) {
return _hashTask!.future; return _hashTask!.future;
} }
@ -58,9 +110,11 @@ class BackgroundSyncManager {
return _hashTask!.whenComplete(() { return _hashTask!.whenComplete(() {
_hashTask = null; _hashTask = null;
}); });
});
} }
Future<void> syncRemote() { Future<void> syncRemote() {
return _withRemoteSyncMutex(() async {
if (_syncTask != null) { if (_syncTask != null) {
return _syncTask!.future; return _syncTask!.future;
} }
@ -71,5 +125,6 @@ class BackgroundSyncManager {
return _syncTask!.whenComplete(() { return _syncTask!.whenComplete(() {
_syncTask = null; _syncTask = null;
}); });
});
} }
} }

View File

@ -73,7 +73,10 @@ class ImmichSliverAppBar extends ConsumerWidget {
onPressed: () => context.pop(), onPressed: () => context.pop(),
), ),
IconButton( IconButton(
onPressed: () => ref.read(backgroundSyncProvider).syncRemote(), onPressed: () {
ref.read(backgroundSyncProvider).syncLocal(full: true);
ref.read(backgroundSyncProvider).syncRemote();
},
icon: const Icon( icon: const Icon(
Icons.sync, Icons.sync,
), ),