Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
3412-pg-fix-empty-group-removal-from-internal-p...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 3412-pg-fix-empty-group-removal-from-internal-pg-state.patch of Package erlang
From 6c4464028b4f7d83ef617dd65af762d5ff112ae3 Mon Sep 17 00:00:00 2001 From: Maxim Fedorov <dane@whatsapp.com> Date: Thu, 11 Mar 2021 13:25:11 -0800 Subject: [PATCH] pg: fix empty group removal from internal pg state pg keeps two copies of state: gen_server state and ETS table for concurrent access. #2866 fixed one potential way to introduce mismatch between internal state and ETS table, and this patch completes the fix. --- lib/kernel/src/pg.erl | 27 ++++++++++++++------------- lib/kernel/test/pg_SUITE.erl | 10 ++++++++++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/kernel/src/pg.erl b/lib/kernel/src/pg.erl index 2ca0b083ad..573d2e6953 100644 --- a/lib/kernel/src/pg.erl +++ b/lib/kernel/src/pg.erl @@ -281,19 +281,7 @@ handle_info({leave, Peer, PidOrPids, Groups}, #state{scope = Scope, nodes = Node case maps:get(Peer, Nodes, []) of {MRef, RemoteMap} -> _ = leave_remote(Scope, PidOrPids, Groups), - NewRemoteMap = lists:foldl( - fun (Group, Acc) -> - case maps:get(Group, Acc) of - PidOrPids -> - maps:remove(Group, Acc); - [PidOrPids] -> - maps:remove(Group, Acc); - Existing when is_pid(PidOrPids) -> - Acc#{Group => lists:delete(PidOrPids, Existing)}; - Existing -> - Acc#{Group => Existing-- PidOrPids} - end - end, RemoteMap, Groups), + NewRemoteMap = leave_update_remote_map(PidOrPids, RemoteMap, Groups), {noreply, State#state{nodes = Nodes#{Peer => {MRef, NewRemoteMap}}}}; [] -> %% Handle race condition: remote node disconnected, but scope process @@ -524,6 +512,19 @@ leave_remote(Scope, Pids, Groups) -> end || Group <- Groups]. +leave_update_remote_map(Pid, RemoteMap, Groups) when is_pid(Pid) -> + leave_update_remote_map([Pid], RemoteMap, Groups); +leave_update_remote_map(Pids, RemoteMap, Groups) -> + lists:foldl( + fun (Group, Acc) -> + case maps:get(Group, Acc) -- Pids of + [] -> + maps:remove(Group, Acc); + Remaining -> + Acc#{Group => Remaining} + end + end, RemoteMap, Groups). + all_local_pids(Monitors) -> maps:to_list(maps:fold( fun(Pid, {_Ref, Groups}, Acc) -> diff --git a/lib/kernel/test/pg_SUITE.erl b/lib/kernel/test/pg_SUITE.erl index f03b8a6a39..3a69e33bcf 100644 --- a/lib/kernel/test/pg_SUITE.erl +++ b/lib/kernel/test/pg_SUITE.erl @@ -295,6 +295,16 @@ empty_group_by_remote_leave(Config) when is_list(Config) -> % empty group should be deleted. ?assertEqual(#{}, NewRemoteMap), + %% another variant of emptying a group remotely: join([Pi1, Pid2]) and leave ([Pid2, Pid1]) + RemotePid2 = erlang:spawn(TwoPeer, forever()), + ?assertEqual(ok, rpc:call(TwoPeer, pg, join, [?FUNCTION_NAME, ?FUNCTION_NAME, [RemotePid, RemotePid2]])), + sync({?FUNCTION_NAME, TwoPeer}), + ?assertEqual([RemotePid, RemotePid2], pg:get_members(?FUNCTION_NAME, ?FUNCTION_NAME)), + %% now leave + ?assertEqual(ok, rpc:call(TwoPeer, pg, leave, [?FUNCTION_NAME, ?FUNCTION_NAME, [RemotePid2, RemotePid]])), + sync({?FUNCTION_NAME, TwoPeer}), + ?assertEqual([], pg:get_members(?FUNCTION_NAME, ?FUNCTION_NAME)), + {state, _, _, #{RemoteNode := {_, NewRemoteMap}}} = sys:get_state(?FUNCTION_NAME), stop_node(TwoPeer, Socket), ok. -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor