|
@@ -119,23 +119,34 @@ create_tables() ->
|
|
|
|
|
|
|
|
%%
|
|
%%
|
|
|
|
|
|
|
|
|
|
+-spec match_routes(emqx_types:topic()) -> [emqx_types:route()].
|
|
|
match_routes(Topic) ->
|
|
match_routes(Topic) ->
|
|
|
Matches = emqx_topic_index:matches(Topic, ?EXTROUTE_TAB, [unique]),
|
|
Matches = emqx_topic_index:matches(Topic, ?EXTROUTE_TAB, [unique]),
|
|
|
%% `unique` opt is not enough, since we keep the original Topic as a part of RouteID
|
|
%% `unique` opt is not enough, since we keep the original Topic as a part of RouteID
|
|
|
lists:ukeysort(#route.dest, [match_to_route(M) || M <- Matches]).
|
|
lists:ukeysort(#route.dest, [match_to_route(M) || M <- Matches]).
|
|
|
|
|
|
|
|
|
|
+-spec lookup_routes(emqx_types:topic()) -> [emqx_types:route()].
|
|
|
lookup_routes(Topic) ->
|
|
lookup_routes(Topic) ->
|
|
|
- Pat = #extroute{entry = emqx_topic_index:make_key(Topic, '$1'), _ = '_'},
|
|
|
|
|
|
|
+ Pat = make_extroute_rec_pat(emqx_topic_index:make_key(Topic, '$1')),
|
|
|
[match_to_route(R#extroute.entry) || Records <- ets:match(?EXTROUTE_TAB, Pat), R <- Records].
|
|
[match_to_route(R#extroute.entry) || Records <- ets:match(?EXTROUTE_TAB, Pat), R <- Records].
|
|
|
|
|
|
|
|
|
|
+-spec topics() -> [emqx_types:topic()].
|
|
|
topics() ->
|
|
topics() ->
|
|
|
- Pat = #extroute{entry = '$1', _ = '_'},
|
|
|
|
|
|
|
+ Pat = make_extroute_rec_pat('$1'),
|
|
|
[emqx_topic_index:get_topic(K) || [K] <- ets:match(?EXTROUTE_TAB, Pat)].
|
|
[emqx_topic_index:get_topic(K) || [K] <- ets:match(?EXTROUTE_TAB, Pat)].
|
|
|
|
|
|
|
|
match_to_route(M) ->
|
|
match_to_route(M) ->
|
|
|
?ROUTE_ID(Cluster, _) = emqx_topic_index:get_id(M),
|
|
?ROUTE_ID(Cluster, _) = emqx_topic_index:get_id(M),
|
|
|
#route{topic = emqx_topic_index:get_topic(M), dest = Cluster}.
|
|
#route{topic = emqx_topic_index:get_topic(M), dest = Cluster}.
|
|
|
|
|
|
|
|
|
|
+%% Make Dialyzer happy
|
|
|
|
|
+make_extroute_rec_pat(Entry) ->
|
|
|
|
|
+ erlang:make_tuple(
|
|
|
|
|
+ record_info(size, extroute),
|
|
|
|
|
+ '_',
|
|
|
|
|
+ [{1, extroute}, {#extroute.entry, Entry}]
|
|
|
|
|
+ ).
|
|
|
|
|
+
|
|
|
%%
|
|
%%
|
|
|
|
|
|
|
|
-record(state, {
|
|
-record(state, {
|
|
@@ -143,12 +154,12 @@ match_to_route(M) ->
|
|
|
actor :: actor(),
|
|
actor :: actor(),
|
|
|
incarnation :: incarnation(),
|
|
incarnation :: incarnation(),
|
|
|
lane :: lane() | undefined,
|
|
lane :: lane() | undefined,
|
|
|
- extra :: map()
|
|
|
|
|
|
|
+ extra = #{} :: map()
|
|
|
}).
|
|
}).
|
|
|
|
|
|
|
|
-type state() :: #state{}.
|
|
-type state() :: #state{}.
|
|
|
|
|
|
|
|
--type env() :: #{timestamp := _Milliseconds}.
|
|
|
|
|
|
|
+-type env() :: #{timestamp => _Milliseconds}.
|
|
|
|
|
|
|
|
-spec actor_init(cluster(), actor(), incarnation(), env()) -> {ok, state()}.
|
|
-spec actor_init(cluster(), actor(), incarnation(), env()) -> {ok, state()}.
|
|
|
actor_init(Cluster, Actor, Incarnation, Env = #{timestamp := Now}) ->
|
|
actor_init(Cluster, Actor, Incarnation, Env = #{timestamp := Now}) ->
|
|
@@ -170,10 +181,8 @@ is_present_incarnation(_State) ->
|
|
|
|
|
|
|
|
-spec list_actors(cluster()) -> [#{actor := actor(), incarnation := incarnation()}].
|
|
-spec list_actors(cluster()) -> [#{actor := actor(), incarnation := incarnation()}].
|
|
|
list_actors(Cluster) ->
|
|
list_actors(Cluster) ->
|
|
|
- Matches = ets:match(
|
|
|
|
|
- emqx_external_router_actor,
|
|
|
|
|
- #actor{id = {Cluster, '$1'}, incarnation = '$2', _ = '_'}
|
|
|
|
|
- ),
|
|
|
|
|
|
|
+ Pat = make_actor_rec_pat([{#actor.id, {Cluster, '$1'}}, {#actor.incarnation, '$2'}]),
|
|
|
|
|
+ Matches = ets:match(emqx_external_router_actor, Pat),
|
|
|
[#{actor => Actor, incarnation => Incr} || [Actor, Incr] <- Matches].
|
|
[#{actor => Actor, incarnation => Incr} || [Actor, Incr] <- Matches].
|
|
|
|
|
|
|
|
mnesia_actor_init(Cluster, Actor, Incarnation, TS) ->
|
|
mnesia_actor_init(Cluster, Actor, Incarnation, TS) ->
|
|
@@ -291,7 +300,8 @@ apply_operation(Entry, MCounter, OpName, Lane) ->
|
|
|
|
|
|
|
|
-spec actor_gc(env()) -> _NumCleaned :: non_neg_integer().
|
|
-spec actor_gc(env()) -> _NumCleaned :: non_neg_integer().
|
|
|
actor_gc(#{timestamp := Now}) ->
|
|
actor_gc(#{timestamp := Now}) ->
|
|
|
- MS = [{#actor{until = '$1', _ = '_'}, [{'<', '$1', Now}], ['$_']}],
|
|
|
|
|
|
|
+ Pat = make_actor_rec_pat([{#actor.until, '$1'}]),
|
|
|
|
|
+ MS = [{Pat, [{'<', '$1', Now}], ['$_']}],
|
|
|
Dead = mnesia:dirty_select(?EXTROUTE_ACTOR_TAB, MS),
|
|
Dead = mnesia:dirty_select(?EXTROUTE_ACTOR_TAB, MS),
|
|
|
try_clean_incarnation(Dead).
|
|
try_clean_incarnation(Dead).
|
|
|
|
|
|
|
@@ -316,9 +326,18 @@ mnesia_assign_lane(Cluster) ->
|
|
|
Lane.
|
|
Lane.
|
|
|
|
|
|
|
|
select_cluster_lanes(Cluster) ->
|
|
select_cluster_lanes(Cluster) ->
|
|
|
- MS = [{#actor{id = {Cluster, '_'}, lane = '$1', _ = '_'}, [], ['$1']}],
|
|
|
|
|
|
|
+ Pat = make_actor_rec_pat([{#actor.id, {Cluster, '_'}}, {#actor.lane, '$1'}]),
|
|
|
|
|
+ MS = [{Pat, [], ['$1']}],
|
|
|
mnesia:select(?EXTROUTE_ACTOR_TAB, MS, write).
|
|
mnesia:select(?EXTROUTE_ACTOR_TAB, MS, write).
|
|
|
|
|
|
|
|
|
|
+%% Make Dialyzer happy
|
|
|
|
|
+make_actor_rec_pat(PosValues) ->
|
|
|
|
|
+ erlang:make_tuple(
|
|
|
|
|
+ record_info(size, actor),
|
|
|
|
|
+ '_',
|
|
|
|
|
+ [{1, actor} | PosValues]
|
|
|
|
|
+ ).
|
|
|
|
|
+
|
|
|
mnesia_actor_heartbeat(ActorID, Incarnation, TS) ->
|
|
mnesia_actor_heartbeat(ActorID, Incarnation, TS) ->
|
|
|
case mnesia:read(?EXTROUTE_ACTOR_TAB, ActorID, write) of
|
|
case mnesia:read(?EXTROUTE_ACTOR_TAB, ActorID, write) of
|
|
|
[#actor{incarnation = Incarnation} = Rec] ->
|
|
[#actor{incarnation = Incarnation} = Rec] ->
|