This commit is contained in:
Feng 2015-12-02 18:01:26 +08:00
parent 0b1540f1db
commit 16f23406a4
64 changed files with 447 additions and 777 deletions

View File

@ -60,26 +60,15 @@
-type mqtt_topic() :: #mqtt_topic{}.
%%------------------------------------------------------------------------------
%% MQTT Subscriber
%% MQTT Subscription
%%------------------------------------------------------------------------------
-record(mqtt_subscriber, {
-record(mqtt_subscription, {
clientid :: binary() | atom(),
topic :: binary(),
subpid :: pid(),
qos = 0 :: 0 | 1 | 2
}).
-type mqtt_subscriber() :: #mqtt_subscriber{}.
%%------------------------------------------------------------------------------
%% P2P Queue Subscriber
%%------------------------------------------------------------------------------
-record(mqtt_queue, {
name :: binary(),
qpid :: pid(),
qos = 0 :: 0 | 1 | 2
}).
-type mqtt_queue() :: #mqtt_queue{}.
-type mqtt_subscription() :: #mqtt_subscription{}.
%%------------------------------------------------------------------------------
%% MQTT Client

View File

@ -19,12 +19,18 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Internal Header.
%%% @doc Internal Header File
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-define(GPROC_POOL(JoinOrLeave, Pool, I),
(begin
case JoinOrLeave of
join -> gproc_pool:connect_worker(Pool, {Pool, Id});
leave -> gproc_pool:disconnect_worker(Pool, {Pool, I})
end
end)).
-define(record_to_proplist(Def, Rec),
lists:zip(record_info(fields, Def),
tl(tuple_to_list(Rec)))).

View File

@ -141,11 +141,18 @@
%% Max Payload Size of retained message
{max_playload_size, 65536}
]},
%% PubSub
%% PubSub and Router
{pubsub, [
%% default should be scheduler numbers
%% {pool_size, 8}
%% Default should be scheduler numbers
%% {pool_size, 8},
%% Route aging time(second)
{shard, true},
{aging, 10}
]},
%% Bridge
{bridge, [
%%TODO: bridge queue size

View File

@ -138,6 +138,15 @@
%% default should be scheduler numbers
%% {pool_size, 8}
]},
%% Router
{router, [
%% Default should be scheduler numbers
%% {pool_size, 8},
%% Route aging time(second)
{aging, 5}
]},
%% Bridge
{bridge, [
%%TODO: bridge queue size

View File

@ -34,6 +34,9 @@
## Valid range is 1-2097151. Default is 1024.
## +zdbbl 8192
## CPU Schedulers
## +sbt db
##-------------------------------------------------------------------------
## Env
##-------------------------------------------------------------------------

View File

@ -19,19 +19,17 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd main module.
%%% @doc emqttd main module.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd).
-author("Feng Lee <feng@emqtt.io>").
-export([start/0, env/1, env/2,
open_listeners/1, close_listeners/1,
load_all_mods/0, is_mod_enabled/1,
is_running/1]).
is_running/1, ensure_pool/3]).
-define(MQTT_SOCKOPTS, [
binary,
@ -130,3 +128,13 @@ is_running(Node) ->
Pid when is_pid(Pid) -> true
end.
%%------------------------------------------------------------------------------
%% @doc Ensure gproc pool exist.
%% @end
%%------------------------------------------------------------------------------
ensure_pool(Pool, Type, Opts) ->
try gproc_pool:new(Pool, Type, Opts)
catch
error:exists -> ok
end.

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd authentication and ACL server.
%%% @doc Authentication and ACL Control Server
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_access_control).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-behaviour(gen_server).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd ACL rule.
%%% @doc emqttd ACL Rule
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_access_rule).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-type who() :: all | binary() |

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% Internal ACL that load rules from etc/acl.config
%%% @doc Internal ACL that load rules from etc/acl.config
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_acl_internal).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-export([all_rules/0]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% ACL module behaviour.
%%% @doc ACL module behaviour
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_acl_mod).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
%%%=============================================================================

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% copy alarm_handler.
%%% @doc Copy alarm_handler
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_alarm).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-behaviour(gen_event).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd application.
%%% @doc emqttd application.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_app).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd_cli.hrl").
-behaviour(application).
@ -72,11 +70,12 @@ start_listeners() ->
start_servers(Sup) ->
Servers = [{"emqttd ctl", emqttd_ctl},
{"emqttd trace", emqttd_trace},
{"emqttd router", {supervisor, emqttd_router_sup}},
{"emqttd pubsub", {supervisor, emqttd_pubsub_sup}},
{"emqttd stats", emqttd_stats},
{"emqttd metrics", emqttd_metrics},
{"emqttd retained", emqttd_retained},
{"emqttd pooler", {supervisor, emqttd_pooler_sup}},
{"emqttd retainer", emqttd_retainer},
{"emqttd pooler", {supervisor, emqttd_pooler}},
{"emqttd client manager", {supervisor, emqttd_cm_sup}},
{"emqttd session manager", {supervisor, emqttd_sm_sup}},
{"emqttd session supervisor", {supervisor, emqttd_session_sup}},

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% Anonymous authentication module.
%%% @doc Anonymous authentication module
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_auth_anonymous).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(emqttd_auth_mod).
-export([init/1, check/3, description/0]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% ClientId Authentication Module.
%%% @doc ClientId Authentication Module
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_auth_clientid).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-export([add_clientid/1, add_clientid/2,

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% LDAP Authentication Module
%%% @doc LDAP Authentication Module
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_auth_ldap).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-import(proplists, [get_value/2, get_value/3]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd authentication behaviour.
%%% @doc emqttd authentication behaviour
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_auth_mod).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
%%%=============================================================================

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% Authentication with username and password.
%%% @doc Authentication with username and password
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_auth_username).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_cli.hrl").

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd bridge.
%%% @doc emqttd bridge
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_bridge).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd bridge supervisor.
%%% @doc Bridge Supervisor
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_bridge_sup).
-author("Feng Lee <feng@emqtt.io>").
-behavior(supervisor).
-export([start_link/0,

View File

@ -19,14 +19,14 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd broker.
%%% @doc emqttd broker
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_broker).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd.hrl").
@ -48,18 +48,16 @@
%% Tick API
-export([start_tick/1, stop_tick/1]).
-behaviour(gen_server).
-define(SERVER, ?MODULE).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(BROKER_TAB, mqtt_broker).
-record(state, {started_at, sys_interval, heartbeat, tick_tref}).
-define(SERVER, ?MODULE).
-define(BROKER_TAB, mqtt_broker).
%% $SYS Topics of Broker
-define(SYSTOP_BROKERS, [
version, % Broker version

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd cli.
%%% @doc emqttd cli
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_cli).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_cli.hrl").

View File

@ -19,14 +19,14 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Client Connection.
%%% @doc MQTT Client Connection
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_client).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd.hrl").
@ -34,8 +34,6 @@
-include("emqttd_internal.hrl").
-behaviour(gen_server).
%% API Function Exports
-export([start_link/2, session/1, info/1, kick/1]).

View File

@ -19,19 +19,19 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Client Manager
%%% @doc MQTT Client Manager
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_cm).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_internal.hrl").
%% API Exports
-export([start_link/2, pool/0]).
-export([start_link/3]).
-export([lookup/1, lookup_proc/1, register/1, unregister/1]).
@ -44,28 +44,27 @@
%% gen_server2 priorities
-export([prioritise_call/4, prioritise_cast/3, prioritise_info/3]).
-record(state, {id, statsfun, monitors}).
-record(state, {pool, id, statsfun, monitors}).
-define(CM_POOL, ?MODULE).
-define(POOL, ?MODULE).
%%%=============================================================================
%%% API
%%%=============================================================================
%%------------------------------------------------------------------------------
%% @doc Start client manager
%% @doc Start Client Manager
%% @end
%%------------------------------------------------------------------------------
-spec start_link(Id, StatsFun) -> {ok, pid()} | ignore | {error, any()} when
Id :: pos_integer(),
-spec start_link(Pool, Id, StatsFun) -> {ok, pid()} | ignore | {error, any()} when
Pool :: atom(),
Id :: pos_integer(),
StatsFun :: fun().
start_link(Id, StatsFun) ->
gen_server2:start_link(?MODULE, [Id, StatsFun], []).
pool() -> ?CM_POOL.
start_link(Pool, Id, StatsFun) ->
gen_server2:start_link(?MODULE, [Pool, Id, StatsFun], []).
%%------------------------------------------------------------------------------
%% @doc Lookup client by clientId
%% @doc Lookup Client by ClientId
%% @end
%%------------------------------------------------------------------------------
-spec lookup(ClientId :: binary()) -> mqtt_client() | undefined.
@ -81,19 +80,18 @@ lookup(ClientId) when is_binary(ClientId) ->
%%------------------------------------------------------------------------------
-spec lookup_proc(ClientId :: binary()) -> pid() | undefined.
lookup_proc(ClientId) when is_binary(ClientId) ->
try ets:lookup_element(mqtt_client, ClientId, #mqtt_client.client_pid) of
Pid -> Pid
try ets:lookup_element(mqtt_client, ClientId, #mqtt_client.client_pid)
catch
error:badarg -> undefined
end.
%%------------------------------------------------------------------------------
%% @doc Register clientId with pid.
%% @doc Register ClientId with Pid.
%% @end
%%------------------------------------------------------------------------------
-spec register(Client :: mqtt_client()) -> ok.
register(Client = #mqtt_client{client_id = ClientId}) ->
CmPid = gproc_pool:pick_worker(?CM_POOL, ClientId),
CmPid = gproc_pool:pick_worker(?POOL, ClientId),
gen_server2:cast(CmPid, {register, Client}).
%%------------------------------------------------------------------------------
@ -102,16 +100,18 @@ register(Client = #mqtt_client{client_id = ClientId}) ->
%%------------------------------------------------------------------------------
-spec unregister(ClientId :: binary()) -> ok.
unregister(ClientId) when is_binary(ClientId) ->
CmPid = gproc_pool:pick_worker(?CM_POOL, ClientId),
CmPid = gproc_pool:pick_worker(?POOL, ClientId),
gen_server2:cast(CmPid, {unregister, ClientId, self()}).
%%%=============================================================================
%%% gen_server callbacks
%%%=============================================================================
init([Id, StatsFun]) ->
gproc_pool:connect_worker(?CM_POOL, {?MODULE, Id}),
{ok, #state{id = Id, statsfun = StatsFun, monitors = dict:new()}}.
init([Pool, Id, StatsFun]) ->
?GPROC_POOL(join, Pool, Id),
{ok, #state{pool = Pool, id = Id,
statsfun = StatsFun,
monitors = dict:new()}}.
prioritise_call(_Req, _From, _Len, _State) ->
1.
@ -172,9 +172,8 @@ handle_info(Info, State) ->
lager:error("Unexpected Info: ~p", [Info]),
{noreply, State}.
terminate(_Reason, #state{id = Id}) ->
gproc_pool:disconnect_worker(?CM_POOL, {?MODULE, Id}),
ok.
terminate(_Reason, #state{pool = Pool, id = Id}) ->
?GPROC_POOL(leave, Pool, Id), ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

View File

@ -19,41 +19,46 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd client manager supervisor.
%%% @doc Client Manager Supervisor.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_cm_sup).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(supervisor).
-include("emqttd.hrl").
-behaviour(supervisor).
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
-define(CM, emqttd_cm).
-define(TAB, mqtt_client).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
ets:new(mqtt_client, [ordered_set, named_table, public,
{keypos, 2}, {write_concurrency, true}]),
Schedulers = erlang:system_info(schedulers),
gproc_pool:new(emqttd_cm:pool(), hash, [{size, Schedulers}]),
StatsFun = emqttd_stats:statsfun('clients/count', 'clients/max'),
Children = lists:map(
fun(I) ->
Name = {emqttd_cm, I},
gproc_pool:add_worker(emqttd_cm:pool(), Name, I),
{Name, {emqttd_cm, start_link, [I, StatsFun]},
permanent, 10000, worker, [emqttd_cm]}
end, lists:seq(1, Schedulers)),
{ok, {{one_for_all, 10, 100}, Children}}.
%% Create client table
create_client_tab(),
%% CM Pool Sup
MFA = {?CM, start_link, [emqttd_stats:statsfun('clients/count', 'clients/max')]},
PoolSup = emqttd_pool_sup:spec(pool_sup, [?CM, hash, erlang:system_info(schedulers), MFA]),
{ok, {{one_for_all, 10, 3600}, [PoolSup]}}.
create_client_tab() ->
case ets:info(?TAB, name) of
undefined ->
ets:new(?TAB, [ordered_set, named_table, public,
{keypos, 2}, {write_concurrency, true}]);
_ ->
ok
end.

View File

@ -19,21 +19,19 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd control.
%%% @doc emqttd control
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_ctl).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd.hrl").
-include("emqttd_cli.hrl").
-behaviour(gen_server).
-define(SERVER, ?MODULE).
%% API Function Exports

View File

@ -19,10 +19,10 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd distribution functions.
%%% @doc emqttd distribution functions
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_dist).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd gen_mod behaviour
%%% @doc emqttd gen_mod behaviour
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_gen_mod).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-ifdef(use_specs).

View File

@ -34,11 +34,12 @@
%%% 4. Sequence: 2 bytes sequence in one process
%%%
%%% @end
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%%-----------------------------------------------------------------------------
-module(emqttd_guid).
-author("Feng Lee <feng@emqtt.io>").
-export([gen/0, new/0, timestamp/1]).
-define(MAX_SEQ, 16#FFFF).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd http publish API and websocket client.
%%% @doc emqttd http publish API and websocket client.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_http).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -21,12 +21,11 @@
%%%-----------------------------------------------------------------------------
%%% @doc client keepalive
%%%
%%% @end
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%%-----------------------------------------------------------------------------
-module(emqttd_keepalive).
-author("Feng Lee <feng@emqtt.io>").
-export([start/3, check/1, cancel/1]).
-record(keepalive, {statfun, statval,

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Message Functions
%%% @doc MQTT Message Functions
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_message).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,21 +19,19 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd metrics. responsible for collecting broker metrics.
%%% @doc emqttd metrics. responsible for collecting broker metrics
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_metrics).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").
-behaviour(gen_server).
-define(SERVER, ?MODULE).
%% API Function Exports

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd mnesia.
%%% @doc emqttd mnesia
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_mnesia).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-export([start/0, cluster/1]).

View File

@ -19,21 +19,19 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd auto subscribe module.
%%% @doc emqttd auto subscribe module.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_mod_autosub).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(emqttd_gen_mod).
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").
-behaviour(emqttd_gen_mod).
-export([load/1, client_connected/3, unload/1]).
-record(state, {topics}).

View File

@ -19,19 +19,17 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd presence management module.
%%% @doc emqttd presence management module
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_mod_presence).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(emqttd_gen_mod).
-include("emqttd.hrl").
-behaviour(emqttd_gen_mod).
-export([load/1, unload/1]).
-export([client_connected/3, client_disconnected/3]).

View File

@ -19,19 +19,17 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd rewrite module.
%%% @doc emqttd rewrite module
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_mod_rewrite).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(emqttd_gen_mod).
-include("emqttd.hrl").
-behaviour(emqttd_gen_mod).
-export([load/1, reload/1, unload/1]).
-export([rewrite/3, rewrite/4]).

View File

@ -19,19 +19,17 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd module supervisor.
%%% @doc emqttd module supervisor.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_mod_sup).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(supervisor).
-include("emqttd.hrl").
-behaviour(supervisor).
%% API
-export([start_link/0, start_child/1, start_child/2]).

View File

@ -46,11 +46,12 @@
%%% otherwise dropped the oldest pending one.
%%%
%%% @end
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%%-----------------------------------------------------------------------------
-module(emqttd_mqueue).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd net utility functions. some functions copied from rabbitmq.
%%% @doc emqttd net utility functions. some functions copied from rabbitmq.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_net).
-author("Feng Lee <feng@emqtt.io>").
-include_lib("kernel/include/inet.hrl").
-export([tcp_name/3, tcp_host/1, getopts/2, setopts/2,

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd options handler.
%%% @doc emqttd options handler.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_opts).
-author("Feng Lee <feng@emqtt.io>").
-export([merge/2, g/2, g/3]).
%%------------------------------------------------------------------------------

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Packet Functions
%%% @doc MQTT Packet Functions
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_packet).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Packet Parser.
%%% @doc MQTT Packet Parser
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_parser).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd plugins.
%%% @doc emqttd plugins.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_plugins).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-export([load/0, unload/0]).

View File

@ -19,32 +19,42 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd pooler.
%%% @doc emqttd pooler.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_pooler).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd_internal.hrl").
%% Start the pool supervisor
-export([start_link/0]).
%% API Exports
-export([start_link/1, submit/1, async_submit/1]).
-export([start_link/2, submit/1, async_submit/1]).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {id}).
-record(state, {pool, id}).
%%------------------------------------------------------------------------------
%% @doc Start Pooler Supervisor.
%% @end
%%------------------------------------------------------------------------------
start_link() ->
emqttd_pool_sup:start_link(pooler, random, {?MODULE, start_link, []}).
%%%=============================================================================
%%% API
%%%=============================================================================
-spec start_link(Id :: pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
start_link(Id) ->
gen_server:start_link({local, name(Id)}, ?MODULE, [Id], []).
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
start_link(Pool, Id) ->
gen_server:start_link({local, name(Id)}, ?MODULE, [Pool, Id], []).
name(Id) ->
list_to_atom(lists:concat([?MODULE, "_", integer_to_list(Id)])).
@ -54,22 +64,24 @@ name(Id) ->
%% @end
%%------------------------------------------------------------------------------
submit(Fun) ->
gen_server:call(gproc_pool:pick_worker(pooler), {submit, Fun}, infinity).
Worker = gproc_pool:pick_worker(pooler),
gen_server:call(Worker, {submit, Fun}, infinity).
%%------------------------------------------------------------------------------
%% @doc Submit work to pooler asynchronously
%% @end
%%------------------------------------------------------------------------------
async_submit(Fun) ->
gen_server:cast(gproc_pool:pick_worker(pooler), {async_submit, Fun}).
Worker = gproc_pool:pick_worker(pooler),
gen_server:cast(Worker, {async_submit, Fun}).
%%%=============================================================================
%%% gen_server callbacks
%%%=============================================================================
init([Id]) ->
gproc_pool:connect_worker(pooler, {pooler, Id}),
{ok, #state{id = Id}}.
init([Pool, Id]) ->
?GPROC_POOL(join, Pool, Id),
{ok, #state{pool = Pool, id = Id}}.
handle_call({submit, Fun}, _From, State) ->
{reply, run(Fun), State};
@ -90,8 +102,8 @@ handle_cast(_Msg, State) ->
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, #state{id = I}) ->
gproc_pool:disconnect_worker(pooler, {pooler, I}), ok.
terminate(_Reason, #state{pool = Pool, id = Id}) ->
?GPROC_POOL(leave, Pool, Id), ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@ -105,4 +117,3 @@ run({M, F, A}) ->
run(Fun) when is_function(Fun) ->
Fun().

View File

@ -1,58 +0,0 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in all
%%% copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd pooler supervisor.
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_pooler_sup).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-behaviour(supervisor).
%% API
-export([start_link/0, start_link/1]).
%% Supervisor callbacks
-export([init/1]).
start_link() ->
start_link(erlang:system_info(schedulers)).
start_link(PoolSize) ->
supervisor:start_link({local, ?MODULE}, ?MODULE, [PoolSize]).
init([PoolSize]) ->
gproc_pool:new(pooler, random, [{size, PoolSize}]),
Children = lists:map(
fun(I) ->
gproc_pool:add_worker(pooler, {pooler, I}, I),
{{emqttd_pooler, I},
{emqttd_pooler, start_link, [I]},
permanent, 5000, worker, [emqttd_pooler]}
end, lists:seq(1, PoolSize)),
{ok, {{one_for_all, 10, 100}, Children}}.

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd protocol.
%%% @doc emqttd protocol.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_protocol).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,19 +19,21 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd pubsub.
%%% @doc emqttd pubsub
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_pubsub).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server2).
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").
-include("emqttd_internal.hrl").
%% Mnesia Callbacks
-export([mnesia/1]).
@ -39,59 +41,42 @@
-copy_mnesia({mnesia, [copy]}).
%% API Exports
-export([start_link/2]).
-export([start_link/3]).
-export([create/1,
subscribe/1, subscribe/2,
unsubscribe/1,
publish/1]).
-export([create/1, subscribe/1, subscribe/2, unsubscribe/1, publish/1]).
%% Local node
-export([dispatch/2, match/1]).
-behaviour(gen_server2).
-export([match/1]).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%% gen_server2 priorities
-export([prioritise_call/4, prioritise_cast/3, prioritise_info/3]).
-record(state, {pool, id}).
-define(POOL, pubsub).
-record(state, {id, submap :: map()}).
-define(ROUTER, emqttd_router).
%%%=============================================================================
%%% Mnesia callbacks
%%%=============================================================================
mnesia(boot) ->
%% p2p queue table
ok = emqttd_mnesia:create_table(queue, [
{type, set},
{ram_copies, [node()]},
{record_name, mqtt_queue},
{attributes, record_info(fields, mqtt_queue)}]),
%% topic table
ok = emqttd_mnesia:create_table(topic, [
{type, bag},
{ram_copies, [node()]},
{record_name, mqtt_topic},
{attributes, record_info(fields, mqtt_topic)}]),
%% local subscriber table, not shared with other nodes
ok = emqttd_mnesia:create_table(subscriber, [
%% subscription table
ok = emqttd_mnesia:create_table(subscription, [
{type, bag},
{ram_copies, [node()]},
{record_name, mqtt_subscriber},
{attributes, record_info(fields, mqtt_subscriber)},
{index, [subpid]},
{local_content, true}]);
{record_name, mqtt_subscription},
{attributes, record_info(fields, mqtt_subscription)}]);
mnesia(copy) ->
ok = emqttd_mnesia:copy_table(queue),
ok = emqttd_mnesia:copy_table(topic),
ok = emqttd_mnesia:copy_table(subscriber).
ok = emqttd_mnesia:copy_table(subscription).
%%%=============================================================================
%%% API
@ -101,11 +86,12 @@ mnesia(copy) ->
%% @doc Start one pubsub server
%% @end
%%------------------------------------------------------------------------------
-spec start_link(Id, Opts) -> {ok, pid()} | ignore | {error, any()} when
-spec start_link(Pool, Id, Opts) -> {ok, pid()} | ignore | {error, any()} when
Pool :: atom(),
Id :: pos_integer(),
Opts :: list().
start_link(Id, Opts) ->
gen_server2:start_link({local, name(Id)}, ?MODULE, [Id, Opts], []).
Opts :: list(tuple()).
start_link(Pool, Id, Opts) ->
gen_server2:start_link({local, name(Id)}, ?MODULE, [Pool, Id, Opts], []).
name(Id) ->
list_to_atom("emqttd_pubsub_" ++ integer_to_list(Id)).
@ -115,38 +101,38 @@ name(Id) ->
%% @end
%%------------------------------------------------------------------------------
-spec create(Topic :: binary()) -> ok | {error, Error :: any()}.
create(<<"$Q/", _Queue/binary>>) ->
%% protecte from queue
{error, cannot_create_queue};
create(Topic) when is_binary(Topic) ->
TopicR = #mqtt_topic{topic = Topic, node = node()},
case mnesia:transaction(fun add_topic/1, [TopicR]) of
{atomic, ok} ->
setstats(topics), ok;
{aborted, Error} ->
{error, Error}
case mnesia:transaction(fun add_topic/1, [#mqtt_topic{topic = Topic, node = node()}]) of
{atomic, ok} -> setstats(topics), ok;
{aborted, Error} -> {error, Error}
end.
%%------------------------------------------------------------------------------
%% @doc Subscribe topic
%% @doc Subscribe Topic
%% @end
%%------------------------------------------------------------------------------
-spec subscribe(Topic, Qos) -> {ok, Qos} when
Topic :: binary(),
Qos :: mqtt_qos() | mqtt_qos_name().
subscribe(Topic, Qos) ->
%%TODO:...
subscribe([{Topic, Qos}]).
-spec subscribe({Topic, Qos} | list({Topic, Qos})) ->
{ok, Qos | list(Qos)} | {error, any()} when
Topic :: binary(),
Qos :: mqtt_qos() | mqtt_qos_name().
subscribe({Topic, Qos}) when is_binary(Topic) andalso (?IS_QOS(Qos) orelse is_atom(Qos)) ->
call({subscribe, self(), Topic, ?QOS_I(Qos)});
%%TODO:...
subscribe([{Topic, Qos}]);
subscribe(Topics = [{_Topic, _Qos} | _]) ->
call({subscribe, self(), [{Topic, ?QOS_I(Qos)} || {Topic, Qos} <- Topics]}).
-spec subscribe(Topic, Qos) -> {ok, Qos} when
Topic :: binary(),
Qos :: mqtt_qos() | mqtt_qos_name().
subscribe(Topic, Qos) ->
subscribe({Topic, Qos}).
subscribe(TopicTable0 = [{_Topic, _Qos} | _]) ->
Self = self(),
TopicTable = [{Topic, ?QOS_I(Qos)} || {Topic, Qos} <- TopicTable0],
?ROUTER:add_routes(TopicTable, Self),
PubSub = gproc_pool:pick_worker(pubsub, Self),
SubReq = {subscribe, Self, TopicTable},
gen_server2:call(PubSub, SubReq, infinity).
%%------------------------------------------------------------------------------
%% @doc Unsubscribe Topic or Topics
@ -154,18 +140,13 @@ subscribe(Topic, Qos) ->
%%------------------------------------------------------------------------------
-spec unsubscribe(binary() | list(binary())) -> ok.
unsubscribe(Topic) when is_binary(Topic) ->
cast({unsubscribe, self(), Topic});
unsubscribe([Topic]);
unsubscribe(Topics = [Topic|_]) when is_binary(Topic) ->
cast({unsubscribe, self(), Topics}).
call(Req) ->
Pid = gproc_pool:pick_worker(?POOL, self()),
gen_server2:call(Pid, Req, infinity).
cast(Msg) ->
Pid = gproc_pool:pick_worker(?POOL, self()),
gen_server2:cast(Pid, Msg).
Self = self(),
?ROUTER:delete_routes(Topics, Self),
PubSub = gproc_pool:pick_worker(pubsub, Self),
gen_server2:cast(PubSub, {unsubscribe, Self, Topics}).
%%------------------------------------------------------------------------------
%% @doc Publish to cluster nodes
@ -178,7 +159,7 @@ publish(Msg = #mqtt_message{from = From}) ->
= emqttd_broker:foldl_hooks('message.publish', [], Msg),
%% Retain message first. Don't create retained topic.
case emqttd_retained:retain(Msg1) of
case emqttd_retainer:retain(Msg1) of
ok ->
%% TODO: why unset 'retain' flag?
publish(Topic, emqttd_message:unset_flag(Msg1));
@ -186,42 +167,12 @@ publish(Msg = #mqtt_message{from = From}) ->
publish(Topic, Msg1)
end.
publish(Queue = <<"$Q/", _/binary>>, Msg = #mqtt_message{qos = Qos}) ->
lists:foreach(
fun(#mqtt_queue{qpid = QPid, qos = SubQos}) ->
Msg1 = if
Qos > SubQos -> Msg#mqtt_message{qos = SubQos};
true -> Msg
end,
QPid ! {dispatch, Msg1}
end, mnesia:dirty_read(queue, Queue));
publish(Topic, Msg) when is_binary(Topic) ->
lists:foreach(fun(#mqtt_topic{topic=Name, node=Node}) ->
case Node =:= node() of
true -> dispatch(Name, Msg);
false -> rpc:cast(Node, ?MODULE, dispatch, [Name, Msg])
end
end, match(Topic)).
%%------------------------------------------------------------------------------
%% @doc Dispatch message locally. should only be called by publish.
%% @end
%%------------------------------------------------------------------------------
-spec dispatch(Topic :: binary(), Msg :: mqtt_message()) -> non_neg_integer().
dispatch(Topic, Msg = #mqtt_message{qos = Qos}) when is_binary(Topic) ->
Subscribers = mnesia:dirty_read(subscriber, Topic),
setstats(dropped, Subscribers =:= []),
lists:foreach(
fun(#mqtt_subscriber{subpid=SubPid, qos = SubQos}) ->
Msg1 = if
Qos > SubQos -> Msg#mqtt_message{qos = SubQos};
true -> Msg
end,
SubPid ! {dispatch, Msg1}
end, Subscribers),
length(Subscribers).
rpc:cast(Node, ?ROUTER, route, [Name, Msg])
end, match(Topic)).
%%TODO: Benchmark and refactor...
-spec match(Topic :: binary()) -> [mqtt_topic()].
match(Topic) when is_binary(Topic) ->
MatchedTopics = mnesia:async_dirty(fun emqttd_trie:match/1, [Topic]),
@ -231,172 +182,38 @@ match(Topic) when is_binary(Topic) ->
%%% gen_server callbacks
%%%=============================================================================
init([Id, _Opts]) ->
%%process_flag(priority, high),
%%process_flag(min_heap_size, 1024*1024),
gproc_pool:connect_worker(pubsub, {?MODULE, Id}),
{ok, #state{id = Id, submap = maps:new()}}.
init([Pool, Id, _Opts]) ->
?GPROC_POOL(join, Pool, Id),
{ok, #state{pool = Pool, id = Id}}.
prioritise_call(Msg, _From, _Len, _State) ->
case Msg of
{subscriber, _, _} -> 1;
_ -> 0
end.
prioritise_cast(Msg, _Len, _State) ->
case Msg of
{unsubscribe, _, _} -> 2;
_ -> 0
end.
prioritise_info(Msg, _Len, _State) ->
case Msg of
{'DOWN', _, _, _, _} -> 3;
_ -> 0
end.
handle_call({subscribe, SubPid, Topics}, _From, State) ->
TopicSubs = lists:map(fun({<<"$Q/", _/binary>> = Queue, Qos}) ->
#mqtt_queue{name = Queue, qpid = SubPid, qos = Qos};
({Topic, Qos}) ->
{#mqtt_topic{topic = Topic, node = node()},
#mqtt_subscriber{topic = Topic, subpid = SubPid, qos = Qos}}
end, Topics),
F = fun() ->
lists:map(fun(QueueR) when is_record(QueueR, mqtt_queue) ->
add_queue(QueueR);
(TopicSub) ->
add_subscriber(TopicSub)
end, TopicSubs)
end,
case mnesia:transaction(F) of
%%TODO: clientId???
handle_call({subscribe, _SubPid, TopicTable}, _From, State) ->
Records = [#mqtt_topic{topic = Topic, node = node()} || {Topic, _Qos} <- TopicTable],
case mnesia:transaction(fun() -> [add_topic(Record) || Record <- Records] end) of
{atomic, _Result} ->
setstats(all),
NewState = monitor_subscriber(SubPid, State),
%%TODO: grant all qos
{reply, {ok, [Qos || {_Topic, Qos} <- Topics]}, NewState};
{reply, {ok, [Qos || {_Topic, Qos} <- TopicTable]}, setstats(State)};
{aborted, Error} ->
{reply, {error, Error}, State}
end;
handle_call({subscribe, SubPid, <<"$Q/", _/binary>> = Queue, Qos}, _From, State) ->
case mnesia:dirty_read(queue, Queue) of
[OldQueueR] -> lager:error("Queue is overwrited by ~p: ~p", [SubPid, OldQueueR]);
[] -> ok
end,
QueueR = #mqtt_queue{name = Queue, qpid = SubPid, qos = Qos},
case mnesia:transaction(fun add_queue/1, [QueueR]) of
{atomic, ok} ->
setstats(queues),
{reply, {ok, Qos}, monitor_subscriber(SubPid, State)};
{aborted, Error} ->
{reply, {error, Error}, State}
end;
handle_call({subscribe, SubPid, Topic, Qos}, _From, State) ->
TopicR = #mqtt_topic{topic = Topic, node = node()},
Subscriber = #mqtt_subscriber{topic = Topic, subpid = SubPid, qos = Qos},
case mnesia:transaction(fun add_subscriber/1, [{TopicR, Subscriber}]) of
{atomic, ok} ->
setstats(all),
{reply, {ok, Qos}, monitor_subscriber(SubPid, State)};
{aborted, Error} ->
{reply, {error, Error}, State}
end;
handle_call(Req, _From, State) ->
lager:error("Bad Request: ~p", [Req]),
{reply, {error, badreq}, State}.
%%TODO: clientId???
handle_cast({unsubscribe, SubPid, Topics}, State) when is_list(Topics) ->
TopicSubs = lists:map(fun(<<"$Q/", _/binary>> = Queue) ->
#mqtt_queue{name = Queue, qpid = SubPid};
(Topic) ->
{#mqtt_topic{topic = Topic, node = node()},
#mqtt_subscriber{topic = Topic, subpid = SubPid, _ = '_'}}
end, Topics),
F = fun() ->
lists:foreach(
fun(QueueR) when is_record(QueueR, mqtt_queue) ->
remove_queue(QueueR);
(TopicSub) ->
remove_subscriber(TopicSub)
end, TopicSubs)
end,
case mnesia:transaction(F) of
{atomic, _} -> ok;
{aborted, Error} -> lager:error("unsubscribe ~p error: ~p", [Topics, Error])
end,
setstats(all),
{noreply, State};
handle_cast({unsubscribe, SubPid, <<"$Q/", _/binary>> = Queue}, State) ->
QueueR = #mqtt_queue{name = Queue, qpid = SubPid},
case mnesia:transaction(fun remove_queue/1, [QueueR]) of
{atomic, _} ->
setstats(queues);
{aborted, Error} ->
lager:error("unsubscribe queue ~s error: ~p", [Queue, Error])
end,
{noreply, State};
handle_cast({unsubscribe, SubPid, Topic}, State) ->
TopicR = #mqtt_topic{topic = Topic, node = node()},
Subscriber = #mqtt_subscriber{topic = Topic, subpid = SubPid, _ = '_'},
case mnesia:transaction(fun remove_subscriber/1, [{TopicR, Subscriber}]) of
{atomic, _} -> ok;
{aborted, Error} -> lager:error("unsubscribe ~s error: ~p", [Topic, Error])
end,
setstats(all),
{noreply, State};
handle_cast(Msg, State) ->
lager:error("Bad Msg: ~p", [Msg]),
{noreply, State}.
handle_info({'DOWN', _Mon, _Type, DownPid, _Info}, State = #state{submap = SubMap}) ->
case maps:is_key(DownPid, SubMap) of
true ->
Node = node(),
F = fun() ->
%% remove queue...
Queues = mnesia:match_object(queue, #mqtt_queue{qpid = DownPid, _ = '_'}, write),
lists:foreach(fun(QueueR) ->
mnesia:delete_object(queue, QueueR, write)
end, Queues),
%% remove subscribers...
Subscribers = mnesia:index_read(subscriber, DownPid, #mqtt_subscriber.subpid),
lists:foreach(fun(Sub = #mqtt_subscriber{topic = Topic}) ->
mnesia:delete_object(subscriber, Sub, write),
try_remove_topic(#mqtt_topic{topic = Topic, node = Node})
end, Subscribers)
end,
case catch mnesia:transaction(F) of
{atomic, _} -> ok;
{aborted, Reason} ->
lager:error("Failed to delete 'DOWN' subscriber ~p: ~p", [DownPid, Reason])
end,
setstats(all),
{noreply, State#state{submap = maps:remove(DownPid, SubMap)}};
false ->
lager:error("Unexpected 'DOWN' from ~p", [DownPid]),
{noreply, State}
end;
handle_info(Info, State) ->
lager:error("Unexpected Info: ~p", [Info]),
{noreply, State}.
terminate(_Reason, _State) ->
TopicR = #mqtt_topic{_ = '_', node = node()},
F = fun() ->
[mnesia:delete_object(topic, R, write) || R <- mnesia:match_object(topic, TopicR, write)]
%%TODO: remove trie??
end,
mnesia:transaction(F),
setstats(all).
terminate(_Reason, #state{pool = Pool, id = Id}) ->
?GPROC_POOL(leave, Pool, Id), setstats(all).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@ -405,9 +222,6 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%%=============================================================================
add_queue(QueueR) ->
mnesia:write(queue, QueueR, write).
add_topic(TopicR = #mqtt_topic{topic = Topic}) ->
case mnesia:wread({topic, Topic}) of
[] ->
@ -420,51 +234,6 @@ add_topic(TopicR = #mqtt_topic{topic = Topic}) ->
end
end.
%% Fix issue #53 - Remove Overlapping Subscriptions
add_subscriber({TopicR, Subscriber = #mqtt_subscriber{topic = Topic, subpid = SubPid, qos = Qos}})
when is_record(TopicR, mqtt_topic) ->
case add_topic(TopicR) of
ok ->
OverlapSubs = [Sub || Sub = #mqtt_subscriber{topic = SubTopic, qos = SubQos}
<- mnesia:index_read(subscriber, SubPid, #mqtt_subscriber.subpid),
SubTopic =:= Topic, SubQos =/= Qos],
%% remove overlapping subscribers
if
length(OverlapSubs) =:= 0 -> ok;
true ->
lager:warning("Remove overlapping subscribers: ~p", [OverlapSubs]),
[mnesia:delete_object(subscriber, OverlapSub, write) || OverlapSub <- OverlapSubs]
end,
%% insert subscriber
mnesia:write(subscriber, Subscriber, write);
Error ->
Error
end.
monitor_subscriber(SubPid, State = #state{submap = SubMap}) ->
NewSubMap = case maps:is_key(SubPid, SubMap) of
false ->
maps:put(SubPid, erlang:monitor(process, SubPid), SubMap);
true ->
SubMap
end,
State#state{submap = NewSubMap}.
remove_queue(#mqtt_queue{name = Name, qpid = Pid}) ->
case mnesia:wread({queue, Name}) of
[R = #mqtt_queue{qpid = Pid}] ->
mnesia:delete(queue, R, write);
_ ->
ok
end.
remove_subscriber({TopicR, Subscriber}) when is_record(TopicR, mqtt_topic) ->
[mnesia:delete_object(subscriber, Sub, write) ||
Sub <- mnesia:match_object(subscriber, Subscriber, write)],
try_remove_topic(TopicR).
try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
case mnesia:read({subscriber, Topic}) of
[] ->
@ -481,24 +250,9 @@ try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
%%% Stats functions
%%%=============================================================================
setstats(all) ->
[setstats(Stat) || Stat <- [queues, topics, subscribers]];
setstats(queues) ->
emqttd_stats:setstats('queues/count', 'queues/max',
mnesia:table_info(queue, size));
setstats(topics) ->
setstats(State) ->
emqttd_stats:setstats('topics/count', 'topics/max',
mnesia:table_info(topic, size));
setstats(subscribers) ->
emqttd_stats:setstats('subscribers/count', 'subscribers/max',
mnesia:table_info(subscriber, size)).
setstats(dropped, false) ->
ignore;
setstats(dropped, true) ->
emqttd_metrics:inc('messages/dropped').
mnesia:table_info(topic, size)), State.
%%%=============================================================================
%%% Trace functions

View File

@ -19,18 +19,18 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd pubsub supervisor.
%%% @doc PubSub Supervisor
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_pubsub_sup).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(supervisor).
-include("emqttd.hrl").
-behaviour(supervisor).
-define(HELPER, emqttd_pubsub_helper).
%% API
-export([start_link/0]).
@ -39,19 +39,42 @@
-export([init/1]).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
Opts = emqttd_broker:env(pubsub),
Schedulers = erlang:system_info(schedulers),
PoolSize = proplists:get_value(pool_size, Opts, Schedulers),
gproc_pool:new(pubsub, hash, [{size, PoolSize}]),
Children = lists:map(
fun(I) ->
Name = {emqttd_pubsub, I},
gproc_pool:add_worker(pubsub, Name, I),
{Name, {emqttd_pubsub, start_link, [I, Opts]},
permanent, 10000, worker, [emqttd_pubsub]}
end, lists:seq(1, PoolSize)),
{ok, {{one_for_all, 10, 100}, Children}}.
supervisor:start_link({local, ?MODULE}, ?MODULE, [Opts]).
init([Opts]) ->
%% Route Table
create_route_tabs(Opts),
%% PubSub Pool Sup
MFA = {emqttd_pubsub, start_link, [Opts]},
PoolSup = emqttd_pool_sup:spec(pool_sup, [
pubsub, hash, pool_size(Opts), MFA]),
%% PubSub Helper
Helper = {helper, {?HELPER, start_link, [Opts]},
permanent, infinity, worker, [?HELPER]},
{ok, {{one_for_all, 10, 60}, [Helper, PoolSup]}}.
pool_size(Opts) ->
Schedulers = erlang:system_info(schedulers),
proplists:get_value(pool_size, Opts, Schedulers).
create_route_tabs(_Opts) ->
TabOpts = [bag, public, named_table,
{write_concurrency, true}],
%% Route Table: Topic -> {Pid, QoS}
%% Route Shard: {Topic, Shard} -> {Pid, QoS}
ensure_tab(route, TabOpts),
%% Reverse Route Table: Pid -> {Topic, QoS}
ensure_tab(reverse_route, TabOpts).
ensure_tab(Tab, Opts) ->
case ets:info(Tab, name) of
undefined ->
ets:new(Tab, Opts);
_ ->
ok
end.

View File

@ -19,16 +19,18 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT retained message storage.
%%% @doc MQTT retained message storage.
%%%
%%% TODO: should match topic tree
%%%
%%%
%%% @end
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%%-----------------------------------------------------------------------------
-module(emqttd_retained).
-module(emqttd_retainer).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd.hrl").
@ -46,8 +48,6 @@
%% API Function Exports
-export([start_link/0, expire/1]).
-behaviour(gen_server).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Packet Serialiser.
%%% @doc MQTT Packet Serialiser
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_serialiser).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").

View File

@ -19,9 +19,7 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%%
%%% Session for persistent MQTT client.
%%% @doc Session for persistent MQTT client.
%%%
%%% Session State in the broker consists of:
%%%
@ -43,11 +41,12 @@
%%% State of Message: newcome, inflight, pending
%%%
%%% @end
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%%-----------------------------------------------------------------------------
-module(emqttd_session).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").
@ -344,7 +343,7 @@ handle_cast({subscribe, TopicTable0, AckFun}, Session = #session{client_id = Cli
%% <MQTT V3.1.1>: 3.8.4
%% Where the Topic Filter is not identical to any existing Subscriptions filter,
%% a new Subscription is created and all matching retained messages are sent.
emqttd_retained:dispatch(Topic, self()),
emqttd_retainer:dispatch(Topic, self()),
[{Topic, Qos} | Acc]
end
end, Subscriptions, TopicTable),

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd session supervisor.
%%% @doc emqttd session supervisor.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_session_sup).
-author("Feng Lee <feng@emqtt.io>").
-behavior(supervisor).
-export([start_link/0, start_session/3]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd session manager.
%%% @doc Session Manager
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_sm).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
%% Mnesia Callbacks
@ -54,7 +52,7 @@
-record(state, {id}).
-define(SM_POOL, ?MODULE).
-define(POOL, ?MODULE).
-define(TIMEOUT, 60000).
@ -92,19 +90,13 @@ start_link(Id) ->
name(Id) ->
list_to_atom("emqttd_sm_" ++ integer_to_list(Id)).
%%------------------------------------------------------------------------------
%% @doc Pool name.
%% @end
%%------------------------------------------------------------------------------
pool() -> ?SM_POOL.
%%------------------------------------------------------------------------------
%% @doc Start a session
%% @end
%%------------------------------------------------------------------------------
-spec start_session(CleanSess :: boolean(), binary()) -> {ok, pid(), boolean()} | {error, any()}.
start_session(CleanSess, ClientId) ->
SM = gproc_pool:pick_worker(?SM_POOL, ClientId),
SM = gproc_pool:pick_worker(?POOL, ClientId),
call(SM, {start_session, {CleanSess, ClientId, self()}}).
%%------------------------------------------------------------------------------
@ -150,7 +142,7 @@ call(SM, Req) ->
%%%=============================================================================
init([Id]) ->
gproc_pool:connect_worker(?SM_POOL, {?MODULE, Id}),
gproc_pool:connect_worker(?POOL, {?MODULE, Id}),
{ok, #state{id = Id}}.
prioritise_call(_Msg, _From, _Len, _State) ->
@ -193,6 +185,7 @@ handle_cast(Msg, State) ->
lager:error("Unexpected Msg: ~p", [Msg]),
{noreply, State}.
%%TODO: fix this issue that index_read is really slow...
handle_info({'DOWN', _MRef, process, DownPid, _Reason}, State) ->
mnesia:transaction(fun() ->
[mnesia:delete_object(session, Sess, write) || Sess
@ -205,7 +198,7 @@ handle_info(Info, State) ->
{noreply, State}.
terminate(_Reason, #state{id = Id}) ->
gproc_pool:disconnect_worker(?SM_POOL, {?MODULE, Id}), ok.
gproc_pool:disconnect_worker(?POOL, {?MODULE, Id}), ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

View File

@ -19,23 +19,21 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd session helper.
%%% @doc Session Helper.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_sm_helper).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
-include("emqttd.hrl").
-include_lib("stdlib/include/ms_transform.hrl").
%% API Function Exports
-export([start_link/0]).
-behaviour(gen_server).
-export([start_link/1]).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@ -47,11 +45,11 @@
%% @doc Start a session helper
%% @end
%%------------------------------------------------------------------------------
-spec start_link() -> {ok, pid()} | ignore | {error, any()}.
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-spec start_link(fun()) -> {ok, pid()} | ignore | {error, any()}.
start_link(StatsFun) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [StatsFun], []).
init([]) ->
init([StatsFun]) ->
mnesia:subscribe(system),
{ok, TRef} = timer:send_interval(timer:seconds(1), tick),
StatsFun = emqttd_stats:statsfun('sessions/count', 'sessions/max'),

View File

@ -19,25 +19,27 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd session manager supervisor.
%%% @doc Session Manager Supervisor.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_sm_sup).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(supervisor).
-include("emqttd.hrl").
-define(CHILD(Mod), {Mod, {Mod, start_link, []},
permanent, 5000, worker, [Mod]}).
-define(SM, emqttd_sm).
-define(HELPER, emqttd_sm_helper).
-define(TABS, [mqtt_transient_session,
mqtt_persistent_session]).
%% API
-export([start_link/0]).
-behaviour(supervisor).
%% Supervisor callbacks
-export([init/1]).
@ -45,20 +47,23 @@ start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
init_session_ets(),
Schedulers = erlang:system_info(schedulers),
gproc_pool:new(emqttd_sm:pool(), hash, [{size, Schedulers}]),
Managers = lists:map(
fun(I) ->
Name = {emqttd_sm, I},
gproc_pool:add_worker(emqttd_sm:pool(), Name, I),
{Name, {emqttd_sm, start_link, [I]},
permanent, 10000, worker, [emqttd_sm]}
end, lists:seq(1, Schedulers)),
{ok, {{one_for_all, 10, 100}, [?CHILD(emqttd_sm_helper) | Managers]}}.
%% Create session tables
create_session_tabs(),
init_session_ets() ->
Tables = [mqtt_transient_session, mqtt_persistent_session],
Attrs = [ordered_set, named_table, public, {write_concurrency, true}],
lists:foreach(fun(Tab) -> ets:new(Tab, Attrs) end, Tables).
%% Helper
StatsFun = emqttd_stats:statsfun('sessions/count', 'sessions/max'),
Helper = {?HELPER, {?HELPER, start_link, [StatsFun]},
permanent, 5000, worker, [?HELPER]},
%% SM Pool Sup
MFA = {?SM, start_link, []},
PoolSup = emqttd_pool_sup:spec(pool_sup, [
?SM, hash, erlang:system_info(schedulers), MFA]),
{ok, {{one_for_all, 10, 3600}, [Helper, PoolSup]}}.
create_session_tabs() ->
Opts = [ordered_set, named_table, public,
{write_concurrency, true}],
[ets:new(Tab, Opts) || Tab <- ?TABS].

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd statistics.
%%% @doc emqttd statistics
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_stats).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-behaviour(gen_server).

View File

@ -19,19 +19,17 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd supervisor.
%%% @doc emqttd top supervisor.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_sup).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(supervisor).
-include("emqttd.hrl").
-behaviour(supervisor).
%% API
-export([start_link/0, start_child/1, start_child/2]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd system monitor.
%%% @doc emqttd system monitor
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_sysmon).
-author("Feng Lee <feng@emqtt.io>").
-behavior(gen_server).
-export([start_link/1]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% MQTT Topic Functions
%%% @doc MQTT Topic Functions
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_topic).
-author("Feng Lee <feng@emqtt.io>").
-import(lists, [reverse/1]).
-export([match/2, validate/1, triples/1, words/1, wildcard/1]).

View File

@ -19,22 +19,20 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% Trace MQTT packets/messages by clientid or topic.
%%% @doc Trace MQTT packets/messages by clientid or topic.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_trace).
-author("Feng Lee <feng@emqtt.io>").
-behaviour(gen_server).
%% API Function Exports
-export([start_link/0]).
-export([start_trace/2, stop_trace/1, all_traces/0]).
-behaviour(gen_server).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

View File

@ -25,11 +25,12 @@
%%% [Trie](http://en.wikipedia.org/wiki/Trie)
%%%
%%% @end
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%%-----------------------------------------------------------------------------
-module(emqttd_trie).
-author("Feng Lee <feng@emqtt.io>").
%% Mnesia Callbacks
-export([mnesia/1]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd utility functions.
%%% @doc emqttd utility functions
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_util).
-author("Feng Lee <feng@emqtt.io>").
-export([apply_module_attributes/1,
all_module_attributes/1,
cancel_timer/1,

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd erlang vm.
%%% @doc emqttd erlang vm.
%%%
%%% @author huangdan
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_vm).
-author('huangdan').
-export([schedulers/0]).
-export([microsecs/0]).

View File

@ -19,15 +19,13 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc
%%% emqttd websocket client.
%%% @doc emqttd websocket client
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%
%%% @end
%%%-----------------------------------------------------------------------------
-module(emqttd_ws_client).
-author("Feng Lee <feng@emqtt.io>").
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").