Add inflight module and test suite
This commit is contained in:
parent
61a54b4b33
commit
08100525a5
|
@ -0,0 +1,94 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io)
|
||||||
|
%%
|
||||||
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
%% you may not use this file except in compliance with the License.
|
||||||
|
%% You may obtain a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing, software
|
||||||
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
%% See the License for the specific language governing permissions and
|
||||||
|
%% limitations under the License.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
%% @doc Inflight Window that wraps the gb_trees.
|
||||||
|
|
||||||
|
-module(emqttd_inflight).
|
||||||
|
|
||||||
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
|
-export([new/1, contain/2, lookup/2, insert/3, update/3, delete/2, values/1,
|
||||||
|
to_list/1, size/1, max_size/1, is_full/1, is_empty/1, window/1]).
|
||||||
|
|
||||||
|
-type(inflight() :: {?MODULE, list()}).
|
||||||
|
|
||||||
|
-export_type([inflight/0]).
|
||||||
|
|
||||||
|
-spec(new(non_neg_integer()) -> inflight()).
|
||||||
|
new(MaxSize) when MaxSize >= 0 ->
|
||||||
|
{?MODULE, [MaxSize, gb_trees:empty()]}.
|
||||||
|
|
||||||
|
-spec(contain(Key :: any(), inflight()) -> boolean()).
|
||||||
|
contain(Key, {?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:is_defined(Key, Tree).
|
||||||
|
|
||||||
|
-spec(lookup(Key :: any(), inflight()) -> any()).
|
||||||
|
lookup(Key, {?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:get(Key, Tree).
|
||||||
|
|
||||||
|
-spec(insert(Key :: any(), Value :: any(), inflight()) -> inflight()).
|
||||||
|
insert(Key, Value, {?MODULE, [MaxSize, Tree]}) ->
|
||||||
|
{?MODULE, [MaxSize, gb_trees:insert(Key, Value, Tree)]}.
|
||||||
|
|
||||||
|
-spec(delete(Key :: any(), inflight()) -> inflight()).
|
||||||
|
delete(Key, {?MODULE, [MaxSize, Tree]}) ->
|
||||||
|
{?MODULE, [MaxSize, gb_trees:delete(Key, Tree)]}.
|
||||||
|
|
||||||
|
-spec(update(Key :: any(), Val :: any(), inflight()) -> inflight()).
|
||||||
|
update(Key, Val, {?MODULE, [MaxSize, Tree]}) ->
|
||||||
|
{?MODULE, [MaxSize, gb_trees:update(Key, Val, Tree)]}.
|
||||||
|
|
||||||
|
-spec(is_full(inflight()) -> boolean()).
|
||||||
|
is_full({?MODULE, [0, _Tree]}) ->
|
||||||
|
false;
|
||||||
|
is_full({?MODULE, [MaxSize, Tree]}) ->
|
||||||
|
MaxSize =< gb_trees:size(Tree).
|
||||||
|
|
||||||
|
-spec(is_empty(inflight()) -> boolean()).
|
||||||
|
is_empty({?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:is_empty(Tree).
|
||||||
|
|
||||||
|
-spec(smallest(inflight()) -> {K :: any(), V :: any()}).
|
||||||
|
smallest({?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:smallest(Tree).
|
||||||
|
|
||||||
|
-spec(largest(inflight()) -> {K :: any(), V :: any()}).
|
||||||
|
largest({?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:largest(Tree).
|
||||||
|
|
||||||
|
-spec(values(inflight()) -> list()).
|
||||||
|
values({?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:values(Tree).
|
||||||
|
|
||||||
|
-spec(to_list(inflight()) -> list({K :: any(), V :: any()})).
|
||||||
|
to_list({?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:to_list(Tree).
|
||||||
|
|
||||||
|
-spec(window(inflight()) -> list()).
|
||||||
|
window(Inflight = {?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
case gb_trees:is_empty(Tree) of
|
||||||
|
true -> [];
|
||||||
|
false -> [Key || {Key, _Val} <- [smallest(Inflight), largest(Inflight)]]
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec(size(inflight()) -> non_neg_integer()).
|
||||||
|
size({?MODULE, [_MaxSize, Tree]}) ->
|
||||||
|
gb_trees:size(Tree).
|
||||||
|
|
||||||
|
-spec(max_size(inflight()) -> non_neg_integer()).
|
||||||
|
max_size({?MODULE, [MaxSize, _Tree]}) ->
|
||||||
|
MaxSize.
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
%% Copyright (c) 2012-2017 Feng Lee <feng@emqtt.io>.
|
|
||||||
%%
|
|
||||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
%% you may not use this file except in compliance with the License.
|
|
||||||
%% You may obtain a copy of the License at
|
|
||||||
%%
|
|
||||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
%%
|
|
||||||
%% Unless required by applicable law or agreed to in writing, software
|
|
||||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
%% See the License for the specific language governing permissions and
|
|
||||||
%% limitations under the License.
|
|
||||||
%%--------------------------------------------------------------------
|
|
||||||
|
|
||||||
-module(emqttd_opts).
|
|
||||||
|
|
||||||
-export([merge/2]).
|
|
||||||
|
|
||||||
%% @doc Merge Options
|
|
||||||
merge(Defaults, Options) ->
|
|
||||||
lists:foldl(
|
|
||||||
fun({Opt, Val}, Acc) ->
|
|
||||||
case lists:keymember(Opt, 1, Acc) of
|
|
||||||
true -> lists:keyreplace(Opt, 1, Acc, {Opt, Val});
|
|
||||||
false -> [{Opt, Val}|Acc]
|
|
||||||
end;
|
|
||||||
(Opt, Acc) ->
|
|
||||||
case lists:member(Opt, Acc) of
|
|
||||||
true -> Acc;
|
|
||||||
false -> [Opt | Acc]
|
|
||||||
end
|
|
||||||
end, Defaults, Options).
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
%%
|
||||||
|
%% Copyright (c) 2013-2017 EMQ Enterprise, Inc. (http://emqtt.io)
|
||||||
|
%%
|
||||||
|
|
||||||
|
-module(emqttd_inflight_SUITE).
|
||||||
|
|
||||||
|
-author("Feng Lee <feng@emqtt.io>").
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
%% CT
|
||||||
|
-compile(export_all).
|
||||||
|
|
||||||
|
all() -> [t_contain, t_lookup, t_insert, t_update, t_delete, t_window,
|
||||||
|
t_is_full, t_is_empty].
|
||||||
|
|
||||||
|
t_contain(_) ->
|
||||||
|
Inflight = emqttd_inflight:new(0),
|
||||||
|
?assertNot(Inflight:contain(k)),
|
||||||
|
Inflight1 = Inflight:insert(k, v),
|
||||||
|
?assert(Inflight1:contain(k)).
|
||||||
|
|
||||||
|
t_lookup(_) ->
|
||||||
|
Inflight = (emqttd_inflight:new(0)):insert(k, v),
|
||||||
|
?assertEqual(v, Inflight:lookup(k)).
|
||||||
|
|
||||||
|
t_insert(_) ->
|
||||||
|
Inflight = ((emqttd_inflight:new(0)):insert(k1, v1)):insert(k2, v2),
|
||||||
|
?assertEqual(v2, Inflight:lookup(k2)).
|
||||||
|
|
||||||
|
t_update(_) ->
|
||||||
|
Inflight = ((emqttd_inflight:new(0)):insert(k, v1)):update(k, v2),
|
||||||
|
?assertEqual(v2, Inflight:lookup(k)).
|
||||||
|
|
||||||
|
t_delete(_) ->
|
||||||
|
Inflight = ((emqttd_inflight:new(0)):insert(k, v1)):delete(k),
|
||||||
|
?assert(Inflight:is_empty()).
|
||||||
|
|
||||||
|
t_window(_) ->
|
||||||
|
?assertEqual([], (emqttd_inflight:new(10)):window()),
|
||||||
|
Inflight = ((emqttd_inflight:new(0)):insert(1, 1)):insert(2, 2),
|
||||||
|
?assertEqual([1, 2], Inflight:window()).
|
||||||
|
|
||||||
|
t_is_full(_) ->
|
||||||
|
Inflight = ((emqttd_inflight:new(1)):insert(k, v1)),
|
||||||
|
?assert(Inflight:is_full()).
|
||||||
|
|
||||||
|
t_is_empty(_) ->
|
||||||
|
Inflight = ((emqttd_inflight:new(1)):insert(k, v1)),
|
||||||
|
?assertNot(Inflight:is_empty()).
|
Loading…
Reference in New Issue