Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot]
fe26cb4df2 Update ghcr.io/devcontainers/features/docker-in-docker Docker tag to v4 2026-06-25 12:11:05 +00:00
4 changed files with 14 additions and 40 deletions

View File

@@ -33,7 +33,7 @@
"libfontconfig1" "libfontconfig1"
] ]
}, },
"ghcr.io/devcontainers/features/docker-in-docker:3": { "ghcr.io/devcontainers/features/docker-in-docker:4": {
"dockerDashComposeVersion": "v2" "dockerDashComposeVersion": "v2"
}, },
"ghcr.io/devcontainers/features/github-cli:1": {}, "ghcr.io/devcontainers/features/github-cli:1": {},

View File

@@ -106,7 +106,5 @@
"TaskDownloadMissingLyrics": "누락된 가사 다운로드", "TaskDownloadMissingLyrics": "누락된 가사 다운로드",
"TaskDownloadMissingLyricsDescription": "가사 다운로드", "TaskDownloadMissingLyricsDescription": "가사 다운로드",
"CleanupUserDataTask": "사용자 데이터 정리 작업", "CleanupUserDataTask": "사용자 데이터 정리 작업",
"CleanupUserDataTaskDescription": "최소 90일 이상 존재하지 않는 미디어에 대한 사용자 데이터(시청 상태, 즐겨찾기 등)를 정리합니다.", "CleanupUserDataTaskDescription": "최소 90일 이상 존재하지 않는 미디어에 대한 사용자 데이터(시청 상태, 즐겨찾기 등)를 정리합니다."
"LyricDownloadFailureFromForItem": "{1}에 대한 가사를 {0}에서 다운로드하지 못했습니다",
"Original": "원본"
} }

View File

@@ -65,13 +65,8 @@ public class ItemPersistenceService : IItemPersistenceService
descendantIds.Add(id); descendantIds.Add(id);
} }
// Use WhereOneOrMany instead of a raw HashSet.Contains so large id sets are bound as a
// single parameter (json_each) rather than one SQL variable per id, which would otherwise
// overflow SQLite's variable limit when deleting many items at once (e.g. migrations).
var ownerIds = descendantIds.ToArray();
var extraIds = context.BaseItems var extraIds = context.BaseItems
.Where(e => e.OwnerId.HasValue) .Where(e => e.OwnerId.HasValue && descendantIds.Contains(e.OwnerId.Value))
.WhereOneOrMany(ownerIds, e => e.OwnerId!.Value)
.Select(e => e.Id) .Select(e => e.Id)
.ToArray(); .ToArray();

View File

@@ -136,38 +136,19 @@ public class FixIncorrectOwnerIdRelationships : IAsyncMigrationRoutine
if (allIdsToDelete.Count > 0) if (allIdsToDelete.Count > 0)
{ {
_logger.LogInformation("Deleting {Count} duplicate database entries...", allIdsToDelete.Count); // Batch-resolve items for metadata path cleanup, then delete all at once
var itemsToDelete = allIdsToDelete
.Select(id => _libraryManager.GetItemById(id))
.Where(item => item is not null)
.ToList();
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete!);
// Delete in batches so progress is visible (item resolution and deletion can take a // Fall back to direct DB deletion for any items that couldn't be resolved via LibraryManager
// long time on large libraries) and so we never issue one massive delete transaction. var deletedIds = itemsToDelete.Select(i => i!.Id).ToHashSet();
const int deleteBatchSize = 500; var unresolvedIds = allIdsToDelete.Where(id => !deletedIds.Contains(id)).ToList();
var deletedSoFar = 0; if (unresolvedIds.Count > 0)
for (var offset = 0; offset < allIdsToDelete.Count; offset += deleteBatchSize)
{ {
cancellationToken.ThrowIfCancellationRequested(); _persistenceService.DeleteItem(unresolvedIds);
var batchIds = allIdsToDelete.GetRange(offset, Math.Min(deleteBatchSize, allIdsToDelete.Count - offset));
// Resolve items for metadata path cleanup, then delete this batch
var itemsToDelete = batchIds
.Select(id => _libraryManager.GetItemById(id))
.Where(item => item is not null)
.ToList();
if (itemsToDelete.Count > 0)
{
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete!);
}
// Fall back to direct DB deletion for any items that couldn't be resolved via LibraryManager
var deletedIds = itemsToDelete.Select(i => i!.Id).ToHashSet();
var unresolvedIds = batchIds.Where(id => !deletedIds.Contains(id)).ToList();
if (unresolvedIds.Count > 0)
{
_persistenceService.DeleteItem(unresolvedIds);
}
deletedSoFar += batchIds.Count;
_logger.LogInformation("Deleting duplicates: {Deleted}/{Total} items", deletedSoFar, allIdsToDelete.Count);
} }
} }