File 2618-pg-to-remove-a-group-from-nodes-when-the-group-is-em.patch of Package erlang
From a94f58b9aeb9072e6167859286903706a53f0915 Mon Sep 17 00:00:00 2001
From: Jechol Lee <mr.jechol@gmail.com>
Date: Thu, 12 Nov 2020 13:40:00 +0900
Subject: [PATCH] pg to remove a group from nodes when the group is empty
---
lib/kernel/src/pg.erl | 4 ++--
lib/kernel/test/pg_SUITE.erl | 27 ++++++++++++++++++++++++++-
2 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/lib/kernel/src/pg.erl b/lib/kernel/src/pg.erl
index 580759a9bf..37265a5db0 100644
--- a/lib/kernel/src/pg.erl
+++ b/lib/kernel/src/pg.erl
@@ -285,9 +285,9 @@ handle_info({leave, Peer, PidOrPids, Groups}, #state{scope = Scope, nodes = Node
fun (Group, Acc) ->
case maps:get(Group, Acc) of
PidOrPids ->
- Acc;
+ maps:remove(Group, Acc);
[PidOrPids] ->
- Acc;
+ maps:remove(Group, Acc);
Existing when is_pid(PidOrPids) ->
Acc#{Group => lists:delete(PidOrPids, Existing)};
Existing ->
diff --git a/lib/kernel/test/pg_SUITE.erl b/lib/kernel/test/pg_SUITE.erl
index 725169cda5..f03b8a6a39 100644
--- a/lib/kernel/test/pg_SUITE.erl
+++ b/lib/kernel/test/pg_SUITE.erl
@@ -43,6 +43,7 @@
overlay_missing/0, overlay_missing/1,
single/0, single/1,
two/1,
+ empty_group_by_remote_leave/0, empty_group_by_remote_leave/1,
thundering_herd/0, thundering_herd/1,
initial/1,
netsplit/1,
@@ -101,7 +102,7 @@ groups() ->
{basic, [parallel], [errors, pg, leave_exit_race, single, overlay_missing]},
{performance, [sequential], [thundering_herd]},
{cluster, [parallel], [process_owner_check, two, initial, netsplit, trisplit, foursplit,
- exchange, nolocal, double, scope_restart, missing_scope_join,
+ exchange, nolocal, double, scope_restart, missing_scope_join, empty_group_by_remote_leave,
disconnected_start, forced_sync, group_leave]}
].
@@ -270,7 +271,31 @@ two(Config) when is_list(Config) ->
stop_node(TwoPeer, Socket),
%% hope that 'nodedown' comes before we route our request
sync(?FUNCTION_NAME),
+ ok.
+
+empty_group_by_remote_leave() ->
+ [{doc, "Empty group should be deleted from nodes."}].
+
+empty_group_by_remote_leave(Config) when is_list(Config) ->
+ {TwoPeer, Socket} = spawn_node(?FUNCTION_NAME, ?FUNCTION_NAME),
+ RemoteNode = rpc:call(TwoPeer, erlang, whereis, [?FUNCTION_NAME]),
+ RemotePid = erlang:spawn(TwoPeer, forever()),
+ % remote join
+ ?assertEqual(ok, rpc:call(TwoPeer, pg, join, [?FUNCTION_NAME, ?FUNCTION_NAME, RemotePid])),
+ sync({?FUNCTION_NAME, TwoPeer}),
+ ?assertEqual([RemotePid], pg:get_members(?FUNCTION_NAME, ?FUNCTION_NAME)),
+ % inspecting internal state is not best practice, but there's no other way to check if the state is correct.
+ {state, _, _, #{RemoteNode := {_, RemoteMap}}} = sys:get_state(?FUNCTION_NAME),
+ ?assertEqual(#{?FUNCTION_NAME => [RemotePid]}, RemoteMap),
+ % remote leave
+ ?assertEqual(ok, rpc:call(TwoPeer, pg, leave, [?FUNCTION_NAME, ?FUNCTION_NAME, RemotePid])),
+ sync({?FUNCTION_NAME, TwoPeer}),
?assertEqual([], pg:get_members(?FUNCTION_NAME, ?FUNCTION_NAME)),
+ {state, _, _, #{RemoteNode := {_, NewRemoteMap}}} = sys:get_state(?FUNCTION_NAME),
+ % empty group should be deleted.
+ ?assertEqual(#{}, NewRemoteMap),
+
+ stop_node(TwoPeer, Socket),
ok.
thundering_herd() ->
--
2.26.2