-
Notifications
You must be signed in to change notification settings - Fork 428
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
Conversation
apps/ejabberd/src/shaper.erl
Outdated
new1(Data). | ||
case ejabberd_config:get_global_option({shaper, Name, global}) of | ||
undefined -> #shaper{}; | ||
none -> #shaper{}; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?)
apps/ejabberd/src/shaper.erl
Outdated
#maxrate{maxrate = MaxRate, | ||
lastrate = 0, | ||
lasttime = now_to_usec(now())}. | ||
TokenGrowth = round(Shaper#shaper.max_rate * (Now - Shaper#shaper.last_update) / Second), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally agree :)
0f0787e
to
8a59854
Compare
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), |
There was a problem hiding this comment.
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)), |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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.
apps/ejabberd/src/ejabberd_c2s.erl
Outdated
handle_info(new_offline_messages, session_established, | ||
#state{pres_last = Presence, pres_invis = Invisible} = StateData) | ||
when Presence =/= undefined orelse Invisible -> | ||
From = StateData#state.jid, |
There was a problem hiding this comment.
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
8a59854
to
5b70305
Compare
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), |
There was a problem hiding this comment.
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)), |
There was a problem hiding this comment.
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.
5b70305
to
348a06b
Compare
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.
348a06b
to
59854a5
Compare
Previous Erlang versions throw different errors on missing keys in map.
84f1d7d
to
3b6c29a
Compare
Thanks! |
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:
monitored_map
module for recurring usecase of storing data bound to peer-process lifetime