Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reimplement shaper as a token bucket. #1213

Merged
merged 11 commits into from
Mar 23, 2017
Merged

Reimplement shaper as a token bucket. #1213

merged 11 commits into from
Mar 23, 2017

Conversation

kzemek
Copy link
Contributor

@kzemek kzemek commented Mar 10, 2017

The previous shaper implementation penalized users for sending
several small packets in burst, causing connection/reconnection
to be greatly delayed. To change this behaviour, this commit
reimplements the shaper as a token bucket:
https://en.wikipedia.org/wiki/Token_bucket .

The PR also fixes several issues that came to light with un-delaying packets:

  • Fixes/reduces severity of stanza racing to SM buffer / mod_offline when recipient "flickers" on and off
    • enables mod_offline for all presets
    • adds monitored_map module for recurring usecase of storing data bound to peer-process lifetime
  • Splits test for notifying unavailable pubsub subscribers and disables the part that never really worked
  • Ensures MUC room won't be routed to after its process stops

new1(Data).
case ejabberd_config:get_global_option({shaper, Name, global}) of
undefined -> #shaper{};
none -> #shaper{};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way that ejabberd_config:get_global_option({shaper, Name, global}) returns none? The old code handles that case but not explicitly and it feels very redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

none is explicit setting for no shaper; it's there in the configs, I guess there's some value in that (e.g. in case we would want to have a different default?)

#maxrate{maxrate = MaxRate,
lastrate = 0,
lasttime = now_to_usec(now())}.
TokenGrowth = round(Shaper#shaper.max_rate * (Now - Shaper#shaper.last_update) / Second),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO an expression like (Now - Shaper#shaper.last_update) / Second deserves its own function so that a code reader immediately knowns what it means.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree :)

@kzemek kzemek force-pushed the reimplement_shaper branch from 0f0787e to 8a59854 Compare March 20, 2017 13:34
LUser :: 'error' | ejabberd:luser() | tuple(),
LServer :: 'error' | ejabberd:lserver() | tuple(),
LResource :: 'error' | ejabberd:lresource() | [byte()] | tuple().
LResource :: 'error' | ejabberd:lresource() | [byte()] | tuple(),
ReplacedSessionsPIDs :: ordsets:ordset(pid()).
check_existing_resources(LUser, LServer, LResource) ->
%% A connection exist with the same resource. We replace it:
Sessions = ?SM_BACKEND:get_sessions(LUser, LServer, LResource),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Don't use macros (like SM_BACKEND on line 862) as module names.

false -> {true, SID}
end
end,
?SM_BACKEND:get_sessions(LUser, LServer)),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Don't use macros (like SM_BACKEND on line 884) as module names.

@@ -285,6 +290,10 @@ init([Host, AccessMaxOfflineMsgs]) ->
%% {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({pop_offline_messages, LUser, LServer}, {Pid, _}, State) ->
Result = ?BACKEND:pop_messages(LUser, LServer),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Don't use macros (like BACKEND on line 294) as module names.

handle_info(new_offline_messages, session_established,
#state{pres_last = Presence, pres_invis = Invisible} = StateData)
when Presence =/= undefined orelse Invisible ->
From = StateData#state.jid,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Compiler:

Warning: variable 'From' is unused

@kzemek kzemek force-pushed the reimplement_shaper branch from 8a59854 to 5b70305 Compare March 20, 2017 14:07
LUser :: 'error' | ejabberd:luser() | tuple(),
LServer :: 'error' | ejabberd:lserver() | tuple(),
LResource :: 'error' | ejabberd:lresource() | [byte()] | tuple().
LResource :: 'error' | ejabberd:lresource() | [byte()] | tuple(),
ReplacedSessionsPIDs :: ordsets:ordset(pid()).
check_existing_resources(LUser, LServer, LResource) ->
%% A connection exist with the same resource. We replace it:
Sessions = ?SM_BACKEND:get_sessions(LUser, LServer, LResource),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Don't use macros (like SM_BACKEND on line 864) as module names.

false -> {true, SID}
end
end,
?SM_BACKEND:get_sessions(LUser, LServer)),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to Elvis:

Don't use macros (like SM_BACKEND on line 886) as module names.

@kzemek kzemek force-pushed the reimplement_shaper branch from 5b70305 to 348a06b Compare March 20, 2017 14:33
kzemek added 7 commits March 20, 2017 16:07
The previous shaper implementation penalized users for sending
several small packets in burst, causing connection/reconnection
to be greatly delayed. To change this behaviour, this  commit
reimplements the shaper as a token bucket:
https://en.wikipedia.org/wiki/Token_bucket .
monitored_map holds values associated with a PID. When the process
dies and the map is notified (via message pass-through), entries
associated with the process are removed from the map.
* Remove the ability to concurrently read and write messages to
  mod_offline backend, giving some needed guarantees for flushing
  messages from replaced C2S.
* If any messages will arrive after offline storage was read, the
  running process will be notified of new messages.
@kzemek kzemek force-pushed the reimplement_shaper branch from 348a06b to 59854a5 Compare March 20, 2017 15:07
@kzemek kzemek force-pushed the reimplement_shaper branch from 84f1d7d to 3b6c29a Compare March 21, 2017 09:16
@kzemek
Copy link
Contributor Author

kzemek commented Mar 22, 2017

@michalwski michalwski merged commit 524ae59 into master Mar 23, 2017
@michalwski michalwski deleted the reimplement_shaper branch March 23, 2017 11:39
@michalwski
Copy link
Contributor

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants