Selaa lähdekoodia

perf(router): receive-mark optimise for short-lived transaction process

Zaiming Shi 4 vuotta sitten
vanhempi
commit
92d3e16d43
1 muutettua tiedostoa jossa 28 lisäystä ja 18 poistoa
  1. 28 18
      src/emqx_router.erl

+ 28 - 18
src/emqx_router.erl

@@ -266,28 +266,38 @@ maybe_trans(Fun, Args) ->
                   end, [])
     end.
 
+%% The created fun only terminates with explicit exception
+-dialyzer({nowarn_function, [trans/2]}).
+
 -spec(trans(function(), list(any())) -> ok | {error, term()}).
 trans(Fun, Args) ->
-    %% trigger selective receive optimization of compiler,
-    %% ideal for handling bursty traffic.
-    Ref = erlang:make_ref(),
-    Owner = self(),
-    {WPid, RefMon} = spawn_monitor(
-                       fun() ->
-                               Res = case mnesia:transaction(Fun, Args) of
-                                         {atomic, Ok} -> Ok;
-                                         {aborted, Reason} -> {error, Reason}
-                                     end,
-                               Owner ! {Ref, Res}
-                       end),
+    {WPid, RefMon} =
+        spawn_monitor(
+            %% NOTE: this is under the assumption that crashes in Fun
+            %% are caught by mnesia:transaction/2.
+            %% Future changes should keep in mind that this process
+            %% always exit with database write result.
+            fun() ->
+                    Res = case mnesia:transaction(Fun, Args) of
+                              {atomic, Ok} -> Ok;
+                              {aborted, Reason} -> {error, Reason}
+                          end,
+                    exit({shutdown, Res})
+            end),
+    %% Receive a 'shutdown' exit to pass result from the short-lived process.
+    %% so the receive below can be receive-mark optimized by the compiler.
+    %%
+    %% If the result is sent as a regular message, we'll have to
+    %% either demonitor (with flush which is essentially a 'receive' since
+    %% the process is no longer alive after the result has been received),
+    %% or use a plain 'receive' to drain the normal 'DOWN' message.
+    %% However the compiler does not optimize this second 'receive'.
     receive
-        {Ref, TransRes} ->
-            receive
-                {'DOWN', RefMon, process, WPid, normal} -> ok
-            end,
-            TransRes;
         {'DOWN', RefMon, process, WPid, Info} ->
-            {error, {trans_crash, Info}}
+            case Info of
+                {shutdown, Result} -> Result;
+                _ -> {error, {trans_crash, Info}}
+            end
     end.
 
 lock_router() ->