-
Notifications
You must be signed in to change notification settings - Fork 4
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
Add initial code #1
Conversation
Use persistent term for metadata Monitor a proxy process
Report time to get the joining lock
db4ba52
to
631af65
Compare
Register name for disco
Remove try-catch
Update readme
Separate operations for delete and delete_many Add more types
To split the business logic from the helpers logic
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.
Nice work 👍 I left some comments that I think could improve readability and maintainability.
src/cets_long.erl
Outdated
case Catch of | ||
true -> just_run_safely(Info#{what => long_task_failed}, Fun); | ||
false -> Fun() | ||
end | ||
after | ||
Diff = diff(Start), | ||
?LOG_INFO(Info#{what => long_task_finished, time_ms => Diff}), | ||
Pid ! stop |
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.
This indent is unnecessary big. I see a similar case in some other places as well. What do you think about plugging in some code formatter, such as https://github.com/WhatsApp/erlfmt? I think it could help us keep the formatting consistent.
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.
I have so many questions to erlfmt :)
At least for nodejs formatters you can configure the style.
That aligning when when
is used is kinda wtf:
resolve(#amp_strategy{deliver = [Value | _]}, #amp_rule{
condition = deliver, value = Value, action = Action
}) when
Action == drop orelse Action == error
->
match;
resolve(#amp_strategy{'match-resource' = Value}, #amp_rule{
condition = 'match-resource', value = any
}) when
Value /= undefined
->
match;
resolve(#amp_strategy{'match-resource' = Value}, #amp_rule{
condition = 'match-resource', value = Value
}) ->
And brackets:
CommandTags = ets:match(
ejabberd_commands,
#ejabberd_commands{
name = '$1',
tags = '$2',
_ = '_'
}
),
Maybe we should use it in mongooseim ;)
src/cets_long.erl
Outdated
Pid = spawn_mon(Info, Parent, Start), | ||
try | ||
case Catch of | ||
true -> just_run_safely(Info#{what => long_task_failed}, Fun); |
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.
Putting what => long_task_failed
in this line suggests that our task has already failed. I think it would be more straightforward if we just put it directly in the logging in line 71.
rebar.config
Outdated
no_opaque, no_fail_call, no_contracts, no_behaviours, | ||
no_undefined_callbacks, unmatched_returns, error_handling, | ||
underspecs | ||
% overspecs, specdiffs |
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.
Please either remove or uncomment this line.
src/cets.app.src
Outdated
{registered, []}, | ||
{applications, [kernel, stdlib]}, | ||
{env, []} | ||
% {mod, {cets_app, []} |
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.
Please either remove or uncomment this line.
src/cets_join.erl
Outdated
Info2 = Info#{local_pid => LocalPid, | ||
remote_pid => RemotePid, remote_node => node(RemotePid)}, | ||
F = fun() -> join1(LockKey, Info2, LocalPid, RemotePid) end, | ||
cets_long:run_safely(Info2#{what => join_failed}, F). |
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.
If I get this correctly, what
key of this map is going to be overwritten in cets_long.erl in every logging line. Could you check it?
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.
If I get this correctly,
what
key of this map is going to be overwritten in cets_long.erl in every logging line. Could you check it?
What's more, this can be misleading especially when debugging/tracing. Finding what => join_failed
in the arguments would suggest that something has already failed.
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.
Additionally, there will be more cets_long
calls inside this cets_long
call. I don't think we need doubled monitors. Maybe skip the outer cets_long
entirely and just catch errors?
end_per_testcase(_, _Config) -> | ||
ok. | ||
|
||
test_multinode(Config) -> |
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.
This test checks a few thing, e.g. joining nodes (both before and after adding data), inserting values, deleting values, bulk operations. Could you split it to minimal test cases where each one tests exactly one thing?
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.
I added more tests for each operation
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.
Ok, but it just doesn't help with the readability of this particular one.
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.
It looks promising 🙂 I added some comments.
README.md
Outdated
- `delete(Server, Key)` - deletes an object from the table. | ||
- `delete_many(Server, Keys)` - deletes several objects from the table. | ||
|
||
cets_join module contains the merging logic. |
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.
cets_join module contains the merging logic. | |
`cets_join` module contains the merging logic. |
README.md
Outdated
|
||
cets_join module contains the merging logic. | ||
|
||
cets_discovery module handles search of new nodes. |
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.
cets_discovery module handles search of new nodes. | |
`cets_discovery` module handles search of new nodes. |
...and it would be good to format the remainder of this page as well.
src/cets.erl
Outdated
stop(Server) -> | ||
gen_server:stop(Server). | ||
|
||
-spec dump(server_ref()) -> Records :: [tuple()]. |
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.
-spec dump(server_ref()) -> Records :: [tuple()]. | |
-spec dump(table_name()) -> Records :: [tuple()]. |
.gitignore
Outdated
@@ -0,0 +1,4 @@ | |||
_build/ | |||
rebar3 |
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.
There is no rebar3
in the repo.
src/cets.erl
Outdated
replicate(From, Msg, #{mon_tab := MonTab, other_servers := Servers}) -> | ||
%% Reply would be routed directly to FromPid | ||
Msg2 = {remote_op, From, Msg}, | ||
replicate2(Servers, Msg2), |
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.
I don't think we gain anything by the increased amount of code and the additional function with a 2
suffix. lists:foreach
is also fine for me - easier to read, debug, understand...
replicate2(Servers, Msg2), | |
[send_to_remote(RemotePid, Msg2) || RemotePid <- Servers], |
src/cets.erl
Outdated
ok. | ||
|
||
apply_backlog(State = #{backlog := Backlog}) -> | ||
apply_backlog_ops(lists:reverse(Backlog), State), |
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.
Same as above.
State#{timer_ref := TimerRef}. | ||
|
||
cancel_old_timer(#{timer_ref := OldRef}) when is_reference(OldRef) -> | ||
_ = erlang:cancel_timer(OldRef), |
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.
What is the point of this pattern match? It has no effect.
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.
prevents from dialyzer warning.
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.
Which option triggers this warning? I see a lot of them enabled. Sometimes it might be better to disable a check if it forces us to write unnecessary code.
init({Tab, Opts}) -> | ||
process_flag(message_queue_data, off_heap), | ||
MonTab = list_to_atom(atom_to_list(Tab) ++ "_mon"), | ||
_ = ets:new(Tab, [ordered_set, named_table, public]), |
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.
Another note: why ordered_set
? It slows down read time. Also: how about allowing some customisation instead of hardcoding the table type?
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.
ordered_set is required for ejabberd_sm to work - for reads all sessions of the user, for example.
Address some review comments
Test each operation of test_multinode separately
prevent cets from killing the processes (and losing ETS data) in the event of accidentally calling it with LocalPid same as RemotePid
Expose mon_pid in cets:info
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.
Looks good 👍
{ok, LocalDump} = remote_or_local_dump(LocalPid), | ||
{ok, RemoteDump} = remote_or_local_dump(RemotePid), |
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.
Actually in some tests the local one is the remote one, they are swapped, that's what I meant.
end_per_testcase(_, _Config) -> | ||
ok. | ||
|
||
test_multinode(Config) -> |
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.
Ok, but it just doesn't help with the readability of this particular one.
test/cets_SUITE.erl
Outdated
{ok, Pid2} = start(Node2, Tab), | ||
{ok, Pid3} = start(Node3, Tab), | ||
{ok, Pid4} = start(Node4, Tab), | ||
ok = join(Node1, Tab, Pid3, Pid1), |
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.
This happens a few times: the first pid is remote, and the second is local, while in the join
function it is the other way around. Maybe don't swap the order to make it easier to understand?
Check readme for description