From e917d00eba93c6ed3b176d6c6288422f31497724 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Sat, 1 Jun 2024 14:19:41 +0000 Subject: [PATCH] Prevent infinite DAG growth In some circumstances where files repeatedly get updated, such as when a .xrl file re-generates a .erl file on each compile run, the DAG analysis would repeatedly re-add edges for this file's dependencies (such as include files) to the DAG. Since the digraph module de-dupes vertices but not edges (duplicate edges is a valid use case), we add an explicit check for edge presence before re-adding them. This should properly prevent unexpected growth of DAG files. From manual testing, we get stability when going from a fresh DAG, but if it already had many dupes, the file size may jump around a bit regardless. --- apps/rebar/src/rebar_compiler_dag.erl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/rebar/src/rebar_compiler_dag.erl b/apps/rebar/src/rebar_compiler_dag.erl index cba13ac2f..e147be9aa 100644 --- a/apps/rebar/src/rebar_compiler_dag.erl +++ b/apps/rebar/src/rebar_compiler_dag.erl @@ -149,12 +149,21 @@ finalise_populate_sources_(G, InDirs, [{Status, {deps, Source, AbsIncls}}|Acc]) {_, _Src, Path, _Label} <- [digraph:edge(G, Edge)], not lists:member(Path, AbsIncls)], %% Add the rest - [digraph:add_edge(G, Source, Incl) || Incl <- AbsIncls], + RemainingEdges = [digraph:edge(G, E) || E <- digraph:out_edges(G, Source), + AbsIncls =/= []], + [digraph:add_edge(G, Source, Incl) || Incl <- AbsIncls, + not in_edges(Source, Incl, RemainingEdges)], %% mark the digraph dirty when there is any change in %% dependencies, for any application in the project mark_dirty(G), finalise_populate_sources_(G, InDirs, Acc). +%% @private look if two vertices `V1' and `V2' exist in an unsorted set +%% of DAG edges (in expanded format). +in_edges(_, _, []) -> false; +in_edges(V1, V2, [{_, V1, V2, []}|_]) -> true; +in_edges(V1, V2, [_|T]) -> in_edges(V1, V2, T). + %% @doc this function scans all the source files found and looks into %% all the `InDirs' for deps (other source files, or files that aren't source %% but still returned by the compiler module) that are related