perf(library): stream scans and optimize queue queries

This commit is contained in:
zarzet
2026-08-18 11:03:05 +07:00
parent 29609b6084
commit 7fc27e8314
28 changed files with 2145 additions and 338 deletions
+76 -36
View File
@@ -481,7 +481,7 @@ class _QueueTabState extends ConsumerState<QueueTab> {
_QueueLibraryPageData? nonEmptyFallback,
}) {
void storePage(_QueueLibraryPageData data) {
final cached = _queueLibraryPageDataCache[request];
final cached = _cachedQueueLibraryPageAt(request, request.offset);
if (shouldRetainQueueLibraryPageSnapshot(
currentIsEmpty: data.isEmpty,
cachedHasContent: cached != null && !cached.isEmpty,
@@ -489,6 +489,17 @@ class _QueueTabState extends ConsumerState<QueueTab> {
)) {
return;
}
final staleRequests = _queueLibraryPageDataCache.keys
.where(
(cachedRequest) =>
cachedRequest.offset == request.offset &&
cachedRequest != request &&
_sameQueueLibraryPageScope(cachedRequest, request),
)
.toList(growable: false);
for (final staleRequest in staleRequests) {
_queueLibraryPageDataCache.remove(staleRequest);
}
_queueLibraryPageDataCache[request] = data;
_trimQueueLibraryPageDataCache(protectedRequest: request);
}
@@ -503,19 +514,7 @@ class _QueueTabState extends ConsumerState<QueueTab> {
final pages = <_QueueLibraryPageData>[];
for (var offset = 0; offset <= request.offset; offset += _libraryPageSize) {
final page =
_queueLibraryPageDataCache[_QueueLibraryPageRequest(
filterMode: request.filterMode,
limit: request.limit,
offset: offset,
searchQuery: request.searchQuery,
filterSource: request.filterSource,
filterQuality: request.filterQuality,
filterFormat: request.filterFormat,
filterMetadata: request.filterMetadata,
sortMode: request.sortMode,
localLibraryEnabled: request.localLibraryEnabled,
)];
final page = _cachedQueueLibraryPageAt(request, offset);
if (page != null) pages.add(page);
}
@@ -569,16 +568,37 @@ class _QueueTabState extends ConsumerState<QueueTab> {
_QueueLibraryPageRequest request,
_QueueLibraryPageRequest protectedRequest,
) {
return request.filterMode == protectedRequest.filterMode &&
return _sameQueueLibraryPageScope(request, protectedRequest) &&
request.limit == protectedRequest.limit &&
request.offset <= protectedRequest.offset &&
request.searchQuery == protectedRequest.searchQuery &&
request.filterSource == protectedRequest.filterSource &&
request.filterQuality == protectedRequest.filterQuality &&
request.filterFormat == protectedRequest.filterFormat &&
request.filterMetadata == protectedRequest.filterMetadata &&
request.sortMode == protectedRequest.sortMode &&
request.localLibraryEnabled == protectedRequest.localLibraryEnabled;
request.offset <= protectedRequest.offset;
}
bool _sameQueueLibraryPageScope(
_QueueLibraryPageRequest a,
_QueueLibraryPageRequest b,
) {
return a.filterMode == b.filterMode &&
a.limit == b.limit &&
a.searchQuery == b.searchQuery &&
a.filterSource == b.filterSource &&
a.filterQuality == b.filterQuality &&
a.filterFormat == b.filterFormat &&
a.filterMetadata == b.filterMetadata &&
a.sortMode == b.sortMode &&
a.localLibraryEnabled == b.localLibraryEnabled;
}
_QueueLibraryPageData? _cachedQueueLibraryPageAt(
_QueueLibraryPageRequest request,
int offset,
) {
for (final entry in _queueLibraryPageDataCache.entries) {
if (entry.key.offset == offset &&
_sameQueueLibraryPageScope(entry.key, request)) {
return entry.value;
}
}
return null;
}
void _trimQueueLibraryPageDataCache({
@@ -1292,19 +1312,39 @@ class _QueueTabState extends ConsumerState<QueueTab> {
nonEmptyFallback: historySnapshotCounts,
);
_QueueLibraryPageRequest pageRequest(String filterMode) =>
_QueueLibraryPageRequest(
filterMode: filterMode,
limit: _libraryPageSize,
offset: _libraryPageOffsetFor(filterMode),
searchQuery: _searchQuery,
filterSource: _filterSource,
filterQuality: _filterQuality,
filterFormat: _filterFormat,
filterMetadata: _filterMetadata,
sortMode: _sortMode,
localLibraryEnabled: localLibraryEnabled,
);
_QueueLibraryPageRequest pageRequest(String filterMode) {
final offset = _libraryPageOffsetFor(filterMode);
final baseRequest = _QueueLibraryPageRequest(
filterMode: filterMode,
limit: _libraryPageSize,
offset: offset,
searchQuery: _searchQuery,
filterSource: _filterSource,
filterQuality: _filterQuality,
filterFormat: _filterFormat,
filterMetadata: _filterMetadata,
sortMode: _sortMode,
localLibraryEnabled: localLibraryEnabled,
);
if (offset == 0) return baseRequest;
final previousPage = _cachedQueueLibraryPageAt(
baseRequest,
offset - _libraryPageSize,
);
return _QueueLibraryPageRequest(
filterMode: baseRequest.filterMode,
limit: baseRequest.limit,
offset: baseRequest.offset,
searchQuery: baseRequest.searchQuery,
filterSource: baseRequest.filterSource,
filterQuality: baseRequest.filterQuality,
filterFormat: baseRequest.filterFormat,
filterMetadata: baseRequest.filterMetadata,
sortMode: baseRequest.sortMode,
localLibraryEnabled: baseRequest.localLibraryEnabled,
cursor: previousPage?.nextCursor,
);
}
final activePageRequest = pageRequest(historyFilterMode);
final activePageValue = ref.watch(
+19 -3
View File
@@ -89,6 +89,7 @@ class _QueueLibraryPageRequest {
final String? filterMetadata;
final String sortMode;
final bool localLibraryEnabled;
final QueueLibraryDbCursor? cursor;
const _QueueLibraryPageRequest({
required this.filterMode,
@@ -101,6 +102,7 @@ class _QueueLibraryPageRequest {
required this.filterMetadata,
required this.sortMode,
required this.localLibraryEnabled,
this.cursor,
});
QueueLibraryDbQuery toDbQuery() => QueueLibraryDbQuery(
@@ -114,6 +116,7 @@ class _QueueLibraryPageRequest {
metadata: filterMetadata,
sortMode: sortMode,
includeLocal: localLibraryEnabled,
cursor: cursor,
);
bool get allowsInMemoryHistoryFallback =>
@@ -141,7 +144,8 @@ class _QueueLibraryPageRequest {
filterFormat == other.filterFormat &&
filterMetadata == other.filterMetadata &&
sortMode == other.sortMode &&
localLibraryEnabled == other.localLibraryEnabled;
localLibraryEnabled == other.localLibraryEnabled &&
cursor == other.cursor;
@override
int get hashCode => Object.hash(
@@ -155,6 +159,7 @@ class _QueueLibraryPageRequest {
filterMetadata,
sortMode,
localLibraryEnabled,
cursor,
);
}
@@ -219,6 +224,7 @@ class _QueueLibraryPageData {
final List<LocalLibraryItem> localItems;
final List<_GroupedAlbum> groupedAlbums;
final List<_GroupedLocalAlbum> groupedLocalAlbums;
final QueueLibraryDbCursor? nextCursor;
const _QueueLibraryPageData({
this.items = const [],
@@ -226,6 +232,7 @@ class _QueueLibraryPageData {
this.localItems = const [],
this.groupedAlbums = const [],
this.groupedLocalAlbums = const [],
this.nextCursor,
});
bool get isEmpty =>
@@ -331,6 +338,7 @@ class _QueueLibraryPageData {
localItems: localItems,
groupedAlbums: groupedAlbums,
groupedLocalAlbums: groupedLocalAlbums,
nextCursor: pages.last.nextCursor,
);
}
@@ -403,7 +411,10 @@ final _queueLibraryPageProvider = FutureProvider.autoDispose
}
final dbQuery = request.toDbQuery();
if (request.filterMode == 'albums') {
final rows = await LibraryDatabase.instance.getQueueAlbumPage(dbQuery);
final page = await LibraryDatabase.instance.getQueueAlbumPageResult(
dbQuery,
);
final rows = page.rows;
final groupedAlbums = <_GroupedAlbum>[];
final groupedLocalAlbums = <_GroupedLocalAlbum>[];
for (final row in rows) {
@@ -439,10 +450,14 @@ final _queueLibraryPageProvider = FutureProvider.autoDispose
return _QueueLibraryPageData(
groupedAlbums: groupedAlbums,
groupedLocalAlbums: groupedLocalAlbums,
nextCursor: page.nextCursor,
);
}
final rows = await LibraryDatabase.instance.getQueueTrackPage(dbQuery);
final page = await LibraryDatabase.instance.getQueueTrackPageResult(
dbQuery,
);
final rows = page.rows;
final items = <UnifiedLibraryItem>[];
final historyItems = <DownloadHistoryItem>[];
final localItems = <LocalLibraryItem>[];
@@ -463,6 +478,7 @@ final _queueLibraryPageProvider = FutureProvider.autoDispose
items: items,
historyItems: historyItems,
localItems: localItems,
nextCursor: page.nextCursor,
);
});
@@ -105,6 +105,9 @@ class _MetadataCandidateArtworkState extends State<_MetadataCandidateArtwork> {
width: 56,
height: 56,
fit: BoxFit.cover,
cacheWidth: (56 * MediaQuery.devicePixelRatioOf(context)).round(),
cacheHeight: (56 * MediaQuery.devicePixelRatioOf(context)).round(),
filterQuality: FilterQuality.low,
)
: coverUrl != null
? CachedCoverImage(
@@ -2434,6 +2437,11 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
width: 112,
height: 112,
fit: BoxFit.cover,
cacheWidth: (112 * MediaQuery.devicePixelRatioOf(context))
.round(),
cacheHeight: (112 * MediaQuery.devicePixelRatioOf(context))
.round(),
filterQuality: FilterQuality.low,
semanticLabel:
context.l10n.editMetadataAutoFillCoverAvailable,
errorBuilder: (_, _, _) => const SizedBox.shrink(),
@@ -2710,6 +2718,11 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
height: 160,
width: 160,
fit: BoxFit.cover,
cacheWidth: (160 * MediaQuery.devicePixelRatioOf(context))
.round(),
cacheHeight: (160 * MediaQuery.devicePixelRatioOf(context))
.round(),
filterQuality: FilterQuality.low,
errorBuilder: (_, _, _) => Container(
width: 160,
height: 160,