Skip to content

Commit

Permalink
Always sort deletes before inserts for the same table to avoid deadlo…
Browse files Browse the repository at this point in the history
…cks.

Fixes #14371
  • Loading branch information
AndriySvyryd authored Sep 10, 2021
1 parent 80cdabe commit e1de574
Show file tree
Hide file tree
Showing 5 changed files with 257 additions and 138 deletions.
31 changes: 30 additions & 1 deletion src/EFCore.Relational/Update/Internal/CommandBatchPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ protected virtual IReadOnlyList<List<IReadOnlyModificationCommand>> TopologicalS

AddUniqueValueEdges(modificationCommandGraph);

return modificationCommandGraph.BatchingTopologicalSort(FormatCycle);
AddSameTableEdges(modificationCommandGraph);

return modificationCommandGraph.BatchingTopologicalSort(static (_, _, edges) => edges.All(e => e is IEntityType), FormatCycle);
}

private string FormatCycle(IReadOnlyList<Tuple<IReadOnlyModificationCommand, IReadOnlyModificationCommand, IEnumerable<IAnnotatable>>> data)
Expand Down Expand Up @@ -765,5 +767,32 @@ private void AddUniqueValueEdges(Multigraph<IReadOnlyModificationCommand, IAnnot
}
}
}

private static void AddSameTableEdges(Multigraph<IReadOnlyModificationCommand, IAnnotatable> modificationCommandGraph)
{
var deletedDictionary = new Dictionary<(string, string?), List<IReadOnlyModificationCommand>>();

foreach (var command in modificationCommandGraph.Vertices)
{
if (command.EntityState == EntityState.Deleted)
{
deletedDictionary.GetOrAddNew((command.TableName, command.Schema)).Add(command);
}
}

foreach (var command in modificationCommandGraph.Vertices)
{
if (command.EntityState == EntityState.Added)
{
if (deletedDictionary.TryGetValue((command.TableName, command.Schema), out var deletedList))
{
foreach (var deleted in deletedList)
{
modificationCommandGraph.AddEdge(deleted, command, command.Entries[0].EntityType);
}
}
}
}
}
}
}
Loading

0 comments on commit e1de574

Please sign in to comment.