From ac5c60b0de2ef93a99f6c39f3e251f526f303964 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Tue, 16 Dec 2014 10:10:01 +0100
Subject: Reimplement storeindb/2 to avoid excessive process communication

As currently implemented, there is one call to asn1db:dbget() and
asn1db:dbput() for each type/value definitions in an ASN.1 specification.

If we check for duplicate definitions locally, we can send all
definitions in a single call.
---
 lib/asn1/src/asn1_db.erl      |  8 +++++-
 lib/asn1/src/asn1ct_check.erl | 60 ++++++++++++++++++++++++++-----------------
 2 files changed, 44 insertions(+), 24 deletions(-)

(limited to 'lib/asn1/src')

diff --git a/lib/asn1/src/asn1_db.erl b/lib/asn1/src/asn1_db.erl
index 48d9dd16d7..5577969727 100644
--- a/lib/asn1/src/asn1_db.erl
+++ b/lib/asn1/src/asn1_db.erl
@@ -19,7 +19,8 @@
 %%
 -module(asn1_db).
 
--export([dbstart/1,dbnew/2,dbload/1,dbload/3,dbsave/2,dbput/3,dbget/2]).
+-export([dbstart/1,dbnew/2,dbload/1,dbload/3,dbsave/2,dbput/2,
+	 dbput/3,dbget/2]).
 -export([dbstop/0]).
 
 -record(state, {parent, monitor, includes, table}).
@@ -44,6 +45,7 @@ dbload(Module) ->
 dbnew(Module, Erule)       -> req({new, Module, Erule}).
 dbsave(OutFile, Module)    -> cast({save, OutFile, Module}).
 dbput(Module, K, V)        -> cast({set, Module, K, V}).
+dbput(Module, Kvs)         -> cast({set, Module, Kvs}).
 dbget(Module, K)           -> req({get, Module, K}).
 dbstop()                   -> Resp = req(stop), erase(?MODULE), Resp.
 
@@ -82,6 +84,10 @@ loop(#state{parent = Parent, monitor = MRef, table = Table,
             [{_, Modtab}] = ets:lookup(Table, Mod),
             ets:insert(Modtab, {K2, V}),
             loop(State);
+        {set, Mod, Kvs} ->
+            [{_, Modtab}] = ets:lookup(Table, Mod),
+            ets:insert(Modtab, Kvs),
+            loop(State);
         {From, {get, Mod, K2}} ->
 	    %% XXX If there is no information for Mod, get_table/3
 	    %% will attempt to load information from an .asn1db
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index c97f6cb5d1..6cbf9614cb 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -5651,32 +5651,46 @@ merge_tags2([H|T],Acc) ->
 merge_tags2([], Acc) ->
     lists:reverse(Acc).
 
-storeindb(S,M) when is_record(M,module) ->
-    TVlist = M#module.typeorval,
-    NewM = M#module{typeorval=findtypes_and_values(TVlist)},
-    asn1_db:dbnew(NewM#module.name, S#state.erule),
-    asn1_db:dbput(NewM#module.name,'MODULE',  NewM),
-    Res = storeindb(#state{mname=NewM#module.name}, TVlist, []),
-    include_default_class(S,NewM#module.name),
+storeindb(S0, #module{name=ModName,typeorval=TVlist0}=M) ->
+    S = S0#state{mname=ModName},
+    TVlist1 = [{asn1ct:get_name_of_def(Def),Def} || Def <- TVlist0],
+    case check_duplicate_defs(S, TVlist1) of
+	ok ->
+	    storeindb_1(S, M, TVlist0, TVlist1);
+	{error,_}=Error ->
+	    Error
+    end.
+
+storeindb_1(S, #module{name=ModName}=M, TVlist0, TVlist) ->
+    NewM = M#module{typeorval=findtypes_and_values(TVlist0)},
+    asn1_db:dbnew(ModName, S#state.erule),
+    asn1_db:dbput(ModName, 'MODULE',  NewM),
+    asn1_db:dbput(ModName, TVlist),
+    include_default_class(S, NewM#module.name),
     include_default_type(NewM#module.name),
-    Res.
+    ok.
 
-storeindb(#state{mname=Module}=S, [H|T], Errors) ->
-    Name = asn1ct:get_name_of_def(H),
-    case asn1_db:dbget(Module, Name) of
-	undefined ->
-	    asn1_db:dbput(Module, Name, H),
-	    storeindb(S, T, Errors);
-	Prev ->
-	    PrevLine = asn1ct:get_pos_of_def(Prev),
-	    Error = return_asn1_error(S, H, {already_defined,Name,PrevLine}),
-	    storeindb(S, T, [Error|Errors])
-    end;
-storeindb(_, [], []) ->
-    ok;
-storeindb(_, [], [_|_]=Errors) ->
-    {error,Errors}.
+check_duplicate_defs(S, Defs) ->
+    Set0 = sofs:relation(Defs),
+    Set1 = sofs:relation_to_family(Set0),
+    Set = sofs:to_external(Set1),
+    case [duplicate_def(S, N, Dup) || {N,[_,_|_]=Dup} <- Set] of
+	[] ->
+	    ok;
+	[_|_]=E ->
+	    {error,lists:append(E)}
+    end.
+
+duplicate_def(S, Name, Dups0) ->
+    Dups1 = [{asn1ct:get_pos_of_def(Def),Def} || Def <- Dups0],
+    [{Prev,_}|Dups] = lists:sort(Dups1),
+    duplicate_def_1(S, Dups, Name, Prev).
 
+duplicate_def_1(S, [{_,Def}|T], Name, Prev) ->
+    E = return_asn1_error(S, Def, {already_defined,Name,Prev}),
+    [E|duplicate_def_1(S, T, Name, Prev)];
+duplicate_def_1(_, [], _, _) ->
+    [].
 
 findtypes_and_values(TVList) ->
     findtypes_and_values(TVList,[],[],[],[],[],[]).%% Types,Values,
-- 
cgit v1.2.3