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 'dart:math' as math;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:immich_mobile/constants/constants.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/asset/base_asset.model.dart';
import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/domain/models/setting.model.dart';
@@ -112,8 +113,19 @@ class TimelineService {
totalAssets - _bufferOffset, 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 // 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), : (len > kTimelineAssetLoadBatchSize ? index : index + count - len),
); );
_buffer = await _assetSource(start, len); try {
_bufferOffset = start; _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); return getAssets(index, count);
} }

View File

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