Skip to content

Commit

Permalink
rebar_compiler_dag: store/load dag using internal knowledge
Browse files Browse the repository at this point in the history
Saves a few seconds when loading DAG with thousands of files.
Unfortunately, uses internal knowledge about digraph implementation.
  • Loading branch information
max-au committed Aug 9, 2020
1 parent b7fea54 commit 543a1b7
Showing 1 changed file with 19 additions and 13 deletions.
32 changes: 19 additions & 13 deletions src/rebar_compiler_dag.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@

-include("rebar.hrl").

-define(DAG_VSN, 3).
-define(DAG_VSN, 4).
-define(DAG_ROOT, "source").
-define(DAG_EXT, ".dag").

-type dag_v() :: {digraph:vertex(), term()} | 'false'.
-type dag_e() :: {digraph:vertex(), digraph:vertex()}.
-type critical_meta() :: term(). % if this changes, the DAG is invalid
-type dag_rec() :: {list(dag_v()), list(dag_e()), critical_meta()}.
-type dag() :: digraph:graph().
-type critical_meta() :: term().

-record(dag, {vsn = ?DAG_VSN :: pos_integer(),
info = {[], [], []} :: dag_rec()}).
meta :: critical_meta(),
vtab :: notable | [tuple()],
etab :: notable | [tuple()],
ntab :: notable | [tuple()]}).

-type dag() :: digraph:graph().

%% @doc You should initialize one DAG per compiler module.
%% `CritMeta' is any contextual information that, if it is found to change,
Expand Down Expand Up @@ -253,19 +255,23 @@ restore_dag(G, File, CritMeta) ->
{ok, Data} ->
%% The CritMeta value is checked and if it doesn't match, we fail
%% the whole restore operation.
#dag{vsn=?DAG_VSN, info={Vs, Es, CritMeta}} = binary_to_term(Data),
[digraph:add_vertex(G, V, LastUpdated) || {V, LastUpdated} <- Vs],
[digraph:add_edge(G, V1, V2, Label) || {_, V1, V2, Label} <- Es],
#dag{vsn=?DAG_VSN, meta = CritMeta, vtab = VTab,
etab = ETab, ntab = NTab} = binary_to_term(Data),
{digraph, VT, ET, NT, false} = G,
true = ets:insert_new(VT, VTab),
true = ets:insert_new(ET, ETab),
true = ets:delete_all_objects(NT),
true = ets:insert(NT, NTab),
ok;
{error, _Err} ->
ok
end.

store_dag(G, File, CritMeta) ->
ok = filelib:ensure_dir(File),
Vs = lists:map(fun(V) -> digraph:vertex(G, V) end, digraph:vertices(G)),
Es = lists:map(fun(E) -> digraph:edge(G, E) end, digraph:edges(G)),
Data = term_to_binary(#dag{info={Vs, Es, CritMeta}}, [{compressed, 2}]),
{digraph, VT, ET, NT, false} = G,
Data = term_to_binary(#dag{meta = CritMeta, vtab = ets:tab2list(VT),
etab = ets:tab2list(ET), ntab = ets:select(NT, [{'_',[],['$_']}])}, [{compressed, 2}]),
file:write_file(File, Data).

%% Drop a file from the digraph if it doesn't exist, and if so,
Expand Down

0 comments on commit 543a1b7

Please sign in to comment.