mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-27 01:50:53 +01:00
Merge pull request #17153 from joshuaboniface/fix-FixIncorrectOwnerIdRelationships
Fix too many SQL variables in DeleteItem for large batch deletes
This commit is contained in:
@@ -65,8 +65,13 @@ public class ItemPersistenceService : IItemPersistenceService
|
||||
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
|
||||
.Where(e => e.OwnerId.HasValue && descendantIds.Contains(e.OwnerId.Value))
|
||||
.Where(e => e.OwnerId.HasValue)
|
||||
.WhereOneOrMany(ownerIds, e => e.OwnerId!.Value)
|
||||
.Select(e => e.Id)
|
||||
.ToArray();
|
||||
|
||||
|
||||
@@ -136,19 +136,38 @@ public class FixIncorrectOwnerIdRelationships : IAsyncMigrationRoutine
|
||||
|
||||
if (allIdsToDelete.Count > 0)
|
||||
{
|
||||
// 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!);
|
||||
_logger.LogInformation("Deleting {Count} duplicate database entries...", allIdsToDelete.Count);
|
||||
|
||||
// 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 = allIdsToDelete.Where(id => !deletedIds.Contains(id)).ToList();
|
||||
if (unresolvedIds.Count > 0)
|
||||
// Delete in batches so progress is visible (item resolution and deletion can take a
|
||||
// long time on large libraries) and so we never issue one massive delete transaction.
|
||||
const int deleteBatchSize = 500;
|
||||
var deletedSoFar = 0;
|
||||
for (var offset = 0; offset < allIdsToDelete.Count; offset += deleteBatchSize)
|
||||
{
|
||||
_persistenceService.DeleteItem(unresolvedIds);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user