|
@@ -91,6 +91,11 @@
|
|
|
-define(MAX_LEN_INFINITY, 0).
|
|
-define(MAX_LEN_INFINITY, 0).
|
|
|
-define(INFO_KEYS, [store_qos0, max_len, len, dropped]).
|
|
-define(INFO_KEYS, [store_qos0, max_len, len, dropped]).
|
|
|
|
|
|
|
|
|
|
+-record(shift_opts, {
|
|
|
|
|
+ multiplier :: non_neg_integer(),
|
|
|
|
|
+ base :: integer()
|
|
|
|
|
+ }).
|
|
|
|
|
+
|
|
|
-record(mqueue, {
|
|
-record(mqueue, {
|
|
|
store_qos0 = false :: boolean(),
|
|
store_qos0 = false :: boolean(),
|
|
|
max_len = ?MAX_LEN_INFINITY :: count(),
|
|
max_len = ?MAX_LEN_INFINITY :: count(),
|
|
@@ -98,7 +103,10 @@
|
|
|
dropped = 0 :: count(),
|
|
dropped = 0 :: count(),
|
|
|
p_table = ?NO_PRIORITY_TABLE :: p_table(),
|
|
p_table = ?NO_PRIORITY_TABLE :: p_table(),
|
|
|
default_p = ?LOWEST_PRIORITY :: priority(),
|
|
default_p = ?LOWEST_PRIORITY :: priority(),
|
|
|
- q = ?PQUEUE:new() :: pq()
|
|
|
|
|
|
|
+ q = ?PQUEUE:new() :: pq(),
|
|
|
|
|
+ shift_opts :: #shift_opts{},
|
|
|
|
|
+ last_p :: non_neg_integer() | undefined,
|
|
|
|
|
+ counter :: non_neg_integer() | undefined
|
|
|
}).
|
|
}).
|
|
|
|
|
|
|
|
-type(mqueue() :: #mqueue{}).
|
|
-type(mqueue() :: #mqueue{}).
|
|
@@ -112,7 +120,8 @@ init(Opts = #{max_len := MaxLen0, store_qos0 := QoS_0}) ->
|
|
|
#mqueue{max_len = MaxLen,
|
|
#mqueue{max_len = MaxLen,
|
|
|
store_qos0 = QoS_0,
|
|
store_qos0 = QoS_0,
|
|
|
p_table = get_opt(priorities, Opts, ?NO_PRIORITY_TABLE),
|
|
p_table = get_opt(priorities, Opts, ?NO_PRIORITY_TABLE),
|
|
|
- default_p = get_priority_opt(Opts)
|
|
|
|
|
|
|
+ default_p = get_priority_opt(Opts),
|
|
|
|
|
+ shift_opts = get_shift_opt(Opts)
|
|
|
}.
|
|
}.
|
|
|
|
|
|
|
|
-spec(info(mqueue()) -> emqx_types:infos()).
|
|
-spec(info(mqueue()) -> emqx_types:infos()).
|
|
@@ -171,9 +180,25 @@ in(Msg = #message{topic = Topic}, MQ = #mqueue{default_p = Dp,
|
|
|
out(MQ = #mqueue{len = 0, q = Q}) ->
|
|
out(MQ = #mqueue{len = 0, q = Q}) ->
|
|
|
0 = ?PQUEUE:len(Q), %% assert, in this case, ?PQUEUE:len should be very cheap
|
|
0 = ?PQUEUE:len(Q), %% assert, in this case, ?PQUEUE:len should be very cheap
|
|
|
{empty, MQ};
|
|
{empty, MQ};
|
|
|
-out(MQ = #mqueue{q = Q, len = Len}) ->
|
|
|
|
|
|
|
+out(MQ = #mqueue{q = Q, len = Len, last_p = undefined, shift_opts = ShiftOpts}) ->
|
|
|
|
|
+ {{value, Val, Prio}, Q1} = ?PQUEUE:out_p(Q), %% Shouldn't fail, since we've checked the length
|
|
|
|
|
+ MQ1 = MQ#mqueue{
|
|
|
|
|
+ q = Q1,
|
|
|
|
|
+ len = Len - 1,
|
|
|
|
|
+ last_p = Prio,
|
|
|
|
|
+ counter = init_counter(Prio, ShiftOpts)
|
|
|
|
|
+ },
|
|
|
|
|
+ {{value, Val}, MQ1};
|
|
|
|
|
+out(MQ = #mqueue{q = Q, counter = 0}) ->
|
|
|
|
|
+ MQ1 = MQ#mqueue{
|
|
|
|
|
+ q = ?PQUEUE:shift(Q),
|
|
|
|
|
+ last_p = undefined
|
|
|
|
|
+ },
|
|
|
|
|
+ out(MQ1);
|
|
|
|
|
+out(MQ = #mqueue{q = Q, len = Len, counter = Cnt}) ->
|
|
|
|
|
+ ct:pal("Cnt ~p", [Cnt]),
|
|
|
{R, Q1} = ?PQUEUE:out(Q),
|
|
{R, Q1} = ?PQUEUE:out(Q),
|
|
|
- {R, MQ#mqueue{q = Q1, len = Len - 1}}.
|
|
|
|
|
|
|
+ {R, MQ#mqueue{q = Q1, len = Len - 1, counter = Cnt - 1}}.
|
|
|
|
|
|
|
|
get_opt(Key, Opts, Default) ->
|
|
get_opt(Key, Opts, Default) ->
|
|
|
case maps:get(Key, Opts, Default) of
|
|
case maps:get(Key, Opts, Default) of
|
|
@@ -194,3 +219,29 @@ get_priority_opt(Opts) ->
|
|
|
%% while the highest 'infinity' is a [{infinity, queue:queue()}]
|
|
%% while the highest 'infinity' is a [{infinity, queue:queue()}]
|
|
|
get_priority(_Topic, ?NO_PRIORITY_TABLE, _) -> ?LOWEST_PRIORITY;
|
|
get_priority(_Topic, ?NO_PRIORITY_TABLE, _) -> ?LOWEST_PRIORITY;
|
|
|
get_priority(Topic, PTab, Dp) -> maps:get(Topic, PTab, Dp).
|
|
get_priority(Topic, PTab, Dp) -> maps:get(Topic, PTab, Dp).
|
|
|
|
|
+
|
|
|
|
|
+init_counter(?HIGHEST_PRIORITY, Opts) ->
|
|
|
|
|
+ Infinity = 1000000,
|
|
|
|
|
+ init_counter(Infinity, Opts);
|
|
|
|
|
+init_counter(Prio, #shift_opts{multiplier = Mult, base = Base}) ->
|
|
|
|
|
+ (Prio + Base) * Mult.
|
|
|
|
|
+
|
|
|
|
|
+get_shift_opt(Opts) ->
|
|
|
|
|
+ Mult = maps:get(shift_multiplier, Opts, 10),
|
|
|
|
|
+ Min = case Opts of
|
|
|
|
|
+ #{p_table := PTab} ->
|
|
|
|
|
+ case maps:size(PTab) of
|
|
|
|
|
+ 0 -> 0;
|
|
|
|
|
+ _ -> lists:min(maps:values(PTab))
|
|
|
|
|
+ end;
|
|
|
|
|
+ _ ->
|
|
|
|
|
+ ?LOWEST_PRIORITY
|
|
|
|
|
+ end,
|
|
|
|
|
+ Base = case Min < 0 of
|
|
|
|
|
+ true -> -Min;
|
|
|
|
|
+ false -> 0
|
|
|
|
|
+ end,
|
|
|
|
|
+ #shift_opts{
|
|
|
|
|
+ multiplier = Mult,
|
|
|
|
|
+ base = Base
|
|
|
|
|
+ }.
|