mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-28 10:30:57 +01:00
Batch duplicate-cleanup deletes in merge migrations
This commit is contained in:
@@ -76,25 +76,36 @@ public class CleanupOrphanedExtras : IAsyncMigrationRoutine
|
||||
|
||||
_logger.LogInformation("Found {Count} orphaned extras to remove", orphanedItemIds.Count);
|
||||
|
||||
// Batch-resolve items for metadata path cleanup, then delete all at once
|
||||
var itemsToDelete = new List<BaseItem>();
|
||||
foreach (var itemId in orphanedItemIds)
|
||||
// Resolve items for metadata path cleanup, then delete in batches so we never issue one
|
||||
// massive delete transaction and progress stays visible on large libraries.
|
||||
_logger.LogInformation("Deleting {Count} orphaned extras...", orphanedItemIds.Count);
|
||||
const int deleteBatchSize = 500;
|
||||
var deletedSoFar = 0;
|
||||
for (var offset = 0; offset < orphanedItemIds.Count; offset += deleteBatchSize)
|
||||
{
|
||||
itemsToDelete.Add(BaseItemMapper.DeserializeBaseItem(
|
||||
new Database.Implementations.Entities.BaseItemEntity()
|
||||
{
|
||||
Id = itemId.Id,
|
||||
Path = itemId.Path,
|
||||
Type = itemId.Type
|
||||
},
|
||||
_logger,
|
||||
null,
|
||||
true)!);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var batch = orphanedItemIds.GetRange(offset, Math.Min(deleteBatchSize, orphanedItemIds.Count - offset));
|
||||
var itemsToDelete = batch
|
||||
.Select(itemId => BaseItemMapper.DeserializeBaseItem(
|
||||
new Database.Implementations.Entities.BaseItemEntity()
|
||||
{
|
||||
Id = itemId.Id,
|
||||
Path = itemId.Path,
|
||||
Type = itemId.Type
|
||||
},
|
||||
_logger,
|
||||
null,
|
||||
true)!)
|
||||
.ToList();
|
||||
|
||||
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete);
|
||||
|
||||
deletedSoFar += batch.Count;
|
||||
_logger.LogInformation("Deleting orphaned extras: {Deleted}/{Total}", deletedSoFar, orphanedItemIds.Count);
|
||||
}
|
||||
|
||||
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete);
|
||||
|
||||
_logger.LogInformation("Successfully removed {Count} orphaned extras", itemsToDelete.Count);
|
||||
_logger.LogInformation("Successfully removed {Count} orphaned extras", orphanedItemIds.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,23 +182,35 @@ public class MergeDuplicateMusicArtists : IAsyncMigrationRoutine
|
||||
// Resolve via LibraryManager so DeleteItemsUnsafeFast can also remove the
|
||||
// %MetadataPath%/artists/<Name> directories that the duplicate stubs left behind.
|
||||
// Fall back to the persistence service for any items the LibraryManager can't resolve.
|
||||
var itemsToDelete = idsToDelete
|
||||
.Select(id => _libraryManager.GetItemById(id))
|
||||
.Where(item => item is not null)
|
||||
.ToList();
|
||||
if (itemsToDelete.Count > 0)
|
||||
// Delete in batches so we never issue one massive delete transaction and progress stays visible.
|
||||
_logger.LogInformation("Deleting {Count} duplicate MusicArtist records...", idsToDelete.Count);
|
||||
const int deleteBatchSize = 500;
|
||||
var deletedSoFar = 0;
|
||||
for (var offset = 0; offset < idsToDelete.Count; offset += deleteBatchSize)
|
||||
{
|
||||
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete!);
|
||||
}
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var deletedIds = itemsToDelete.Select(i => i!.Id).ToHashSet();
|
||||
var unresolvedIds = idsToDelete.Where(id => !deletedIds.Contains(id)).ToList();
|
||||
if (unresolvedIds.Count > 0)
|
||||
{
|
||||
_persistenceService.DeleteItem(unresolvedIds);
|
||||
}
|
||||
var batchIds = idsToDelete.GetRange(offset, Math.Min(deleteBatchSize, idsToDelete.Count - offset));
|
||||
|
||||
_logger.LogInformation("Removed {Count} duplicate MusicArtist records.", idsToDelete.Count);
|
||||
var itemsToDelete = batchIds
|
||||
.Select(id => _libraryManager.GetItemById(id))
|
||||
.Where(item => item is not null)
|
||||
.ToList();
|
||||
if (itemsToDelete.Count > 0)
|
||||
{
|
||||
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete!);
|
||||
}
|
||||
|
||||
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 duplicate MusicArtist records: {Deleted}/{Total}", deletedSoFar, idsToDelete.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,23 +184,35 @@ public class MergeDuplicatePeople : IAsyncMigrationRoutine
|
||||
|
||||
// Resolve via LibraryManager so DeleteItemsUnsafeFast can also remove the
|
||||
// %MetadataPath%/People/<Letter>/<Name> directories the duplicate stubs left behind.
|
||||
var itemsToDelete = idsToDelete
|
||||
.Select(id => _libraryManager.GetItemById(id))
|
||||
.Where(item => item is not null)
|
||||
.ToList();
|
||||
if (itemsToDelete.Count > 0)
|
||||
// Delete in batches so we never issue one massive delete transaction and progress stays visible.
|
||||
_logger.LogInformation("Deleting {Count} duplicate Person BaseItems...", idsToDelete.Count);
|
||||
const int deleteBatchSize = 500;
|
||||
var deletedSoFar = 0;
|
||||
for (var offset = 0; offset < idsToDelete.Count; offset += deleteBatchSize)
|
||||
{
|
||||
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete!);
|
||||
}
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var deletedIds = itemsToDelete.Select(i => i!.Id).ToHashSet();
|
||||
var unresolvedIds = idsToDelete.Where(id => !deletedIds.Contains(id)).ToList();
|
||||
if (unresolvedIds.Count > 0)
|
||||
{
|
||||
_persistenceService.DeleteItem(unresolvedIds);
|
||||
}
|
||||
var batchIds = idsToDelete.GetRange(offset, Math.Min(deleteBatchSize, idsToDelete.Count - offset));
|
||||
|
||||
_logger.LogInformation("Removed {Count} duplicate Person BaseItems.", idsToDelete.Count);
|
||||
var itemsToDelete = batchIds
|
||||
.Select(id => _libraryManager.GetItemById(id))
|
||||
.Where(item => item is not null)
|
||||
.ToList();
|
||||
if (itemsToDelete.Count > 0)
|
||||
{
|
||||
_libraryManager.DeleteItemsUnsafeFast(itemsToDelete!);
|
||||
}
|
||||
|
||||
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 duplicate Person BaseItems: {Deleted}/{Total}", deletedSoFar, idsToDelete.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MergePeoplesRowsAsync(JellyfinDbContext context, CancellationToken cancellationToken)
|
||||
|
||||
Reference in New Issue
Block a user