Compare commits

...

1 Commits

Author SHA1 Message Date
Alex
36cffbd44a chore: attempt to handle database lock error when scrubbing the timeline 2025-07-17 11:39:06 -05:00
2 changed files with 70 additions and 40 deletions

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:math' as math;
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:immich_mobile/constants/constants.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/setting.model.dart';
@@ -112,8 +113,19 @@ class TimelineService {
totalAssets - _bufferOffset,
);
}
_buffer = await _assetSource(offset, count);
_bufferOffset = offset;
try {
_buffer = await _assetSource(offset, count);
_bufferOffset = offset;
} catch (e) {
if (e.toString().contains('database has been locked')) {
debugPrint(
"TimelineService::loadAssets - Database locked, returning cached assets",
);
return;
}
rethrow;
}
}
// change the state's total assets count only after the buffer is reloaded
@@ -153,8 +165,22 @@ class TimelineService {
: (len > kTimelineAssetLoadBatchSize ? index : index + count - len),
);
_buffer = await _assetSource(start, len);
_bufferOffset = start;
try {
_buffer = await _assetSource(start, len);
_bufferOffset = start;
} catch (e) {
if (e.toString().contains('database has been locked') &&
_buffer.isNotEmpty) {
debugPrint(
"TimelineService::loadAssets - Database locked, returning cached assets",
);
if (hasRange(index, count)) {
return getAssets(index, count);
}
return <BaseAsset>[];
}
rethrow;
}
return getAssets(index, count);
}

View File

@@ -254,42 +254,44 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
required int offset,
required int count,
}) async {
final albumData = await (_db.remoteAlbumEntity.select()
..where((row) => row.id.equals(albumId)))
.getSingleOrNull();
return await transaction(() async {
final albumData = await (_db.remoteAlbumEntity.select()
..where((row) => row.id.equals(albumId)))
.getSingleOrNull();
// If album doesn't exist (was deleted), return empty list
if (albumData == null) {
return <BaseAsset>[];
}
// If album doesn't exist (was deleted), return empty list
if (albumData == null) {
return <BaseAsset>[];
}
final isAscending = albumData.order == AlbumAssetOrder.asc;
final isAscending = albumData.order == AlbumAssetOrder.asc;
final query = _db.remoteAssetEntity.select().join(
[
innerJoin(
_db.remoteAlbumAssetEntity,
_db.remoteAlbumAssetEntity.assetId
.equalsExp(_db.remoteAssetEntity.id),
useColumns: false,
),
],
)..where(
_db.remoteAssetEntity.deletedAt.isNull() &
_db.remoteAlbumAssetEntity.albumId.equals(albumId),
);
final query = _db.remoteAssetEntity.select().join(
[
innerJoin(
_db.remoteAlbumAssetEntity,
_db.remoteAlbumAssetEntity.assetId
.equalsExp(_db.remoteAssetEntity.id),
useColumns: false,
),
],
)..where(
_db.remoteAssetEntity.deletedAt.isNull() &
_db.remoteAlbumAssetEntity.albumId.equals(albumId),
);
if (isAscending) {
query.orderBy([OrderingTerm.asc(_db.remoteAssetEntity.createdAt)]);
} else {
query.orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]);
}
if (isAscending) {
query.orderBy([OrderingTerm.asc(_db.remoteAssetEntity.createdAt)]);
} else {
query.orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)]);
}
query.limit(count, offset: offset);
query.limit(count, offset: offset);
return query
.map((row) => row.readTable(_db.remoteAssetEntity).toDto())
.get();
return query
.map((row) => row.readTable(_db.remoteAssetEntity).toDto())
.get();
});
}
TimelineQuery remote(String ownerId, GroupAssetsBy groupBy) =>
@@ -462,13 +464,15 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
required Expression<bool> Function($RemoteAssetEntityTable row) filter,
required int offset,
required int count,
}) {
final query = _db.remoteAssetEntity.select()
..where(filter)
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
..limit(count, offset: offset);
}) async {
return await transaction(() async {
final query = _db.remoteAssetEntity.select()
..where(filter)
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
..limit(count, offset: offset);
return query.map((row) => row.toDto()).get();
return query.map((row) => row.toDto()).get();
});
}
}