Browse Source

Improved support for 'r' objects (#183)

* WIP More consistent coverage for 'r' objects

* Rebase, fix whitespace in context

* Apply suggestions from code review

Accept review comments

Co-authored-by: Tino Breddin <tolbrino@users.noreply.github.com>

Co-authored-by: Tino Breddin <tolbrino@users.noreply.github.com>
Ulf Wiger 4 years ago
parent
commit
3737f2b958
5 changed files with 211 additions and 108 deletions
  1. 66 44
      src/gproc.erl
  2. 50 31
      src/gproc_dist.erl
  3. 21 19
      src/gproc_lib.erl
  4. 59 14
      test/gproc_dist_tests.erl
  5. 15 0
      test/gproc_tests.erl

+ 66 - 44
src/gproc.erl

@@ -112,6 +112,8 @@
          lookup_global_properties/1,
          lookup_local_counters/1,
          lookup_global_counters/1,
+         lookup_local_resources/1,
+         lookup_global_resources/1,
          lookup_local_aggr_counter/1,
          lookup_global_aggr_counter/1]).
 
@@ -354,6 +356,25 @@ lookup_local_counters(P)    -> lookup_values({c,l,P}).
 %%
 lookup_global_counters(P)   -> lookup_values({c,g,P}).
 
+%% @spec (Resource::any()) -> [{pid(), Value::integer()}]
+%%
+%% @doc Look up all local (non-unique) instances of a given Resource.
+%% Returns a list of {Pid, Value} tuples for all matching objects.
+%% @equiv lookup_values({r, l, Resource})
+%% @end
+%%
+lookup_local_resources(P)    -> lookup_values({r,l,P}).
+
+
+%% @spec (Resource::any()) -> [{pid(), Value::integer()}]
+%%
+%% @doc Look up all global (non-unique) instances of a given Resource.
+%% Returns a list of {Pid, Value} tuples for all matching objects.
+%% @equiv lookup_values({r, g, Resource})
+%% @end
+%%
+lookup_global_resources(P)   -> lookup_values({r,g,P}).
+
 %% @spec get_env(Scope::scope(), App::atom(), Key::atom()) -> term()
 %% @equiv get_env(Scope, App, Key, [app_env])
 get_env(Scope, App, Key) ->
@@ -933,10 +954,10 @@ monitor(Key, Type) when Type==info;
                         Type==standby ->
     ?CATCH_GPROC_ERROR(monitor1(Key, Type), [Key, Type]).
 
-monitor1({T,g,_} = Key, Type) when T==n; T==a ->
+monitor1({T,g,_} = Key, Type) when T==n; T==a; T==rc ->
     ?CHK_DIST,
     gproc_dist:monitor(Key, Type);
-monitor1({T,l,_} = Key, Type) when T==n; T==a ->
+monitor1({T,l,_} = Key, Type) when T==n; T==a; T==rc ->
     call({monitor, Key, self(), Type}, l);
 monitor1(_, _) ->
     ?THROW_GPROC_ERROR(badarg).
@@ -950,10 +971,10 @@ monitor1(_, _) ->
 demonitor(Key, Ref) ->
     ?CATCH_GPROC_ERROR(demonitor1(Key, Ref), [Key, Ref]).
 
-demonitor1({T,g,_} = Key, Ref) when T==n; T==a ->
+demonitor1({T,g,_} = Key, Ref) when T==n; T==a; T==rc ->
     ?CHK_DIST,
     gproc_dist:demonitor(Key, Ref);
-demonitor1({T,l,_} = Key, Ref) when T==n; T==a ->
+demonitor1({T,l,_} = Key, Ref) when T==n; T==a; T==rc ->
     call({demonitor, Key, Ref, self()}, l);
 demonitor1(_, _) ->
     ?THROW_GPROC_ERROR(badarg).
@@ -1169,7 +1190,7 @@ reg_shared(Key) ->
     ?CATCH_GPROC_ERROR(reg_shared1(valid_key(Key)), [Key]).
 
 %% @private
-reg_shared1({T,_,_} = Key) when T==a; T==p; T==c ->
+reg_shared1({T,_,_} = Key) when T==a; T==p; T==c; T==r ->
     reg_shared(Key, default(Key)).
 
 %% @spec reg_shared(Key::key(), Value) -> true
@@ -1247,7 +1268,7 @@ munreg(T, C, L) ->
 munreg1(T, g, L) ->
     ?CHK_DIST,
     gproc_dist:munreg(T, existing(T,g,L));
-munreg1(T, l, L) when T==a; T==n ->
+munreg1(T, l, L) when T==p; T==a; T==n; T==rc; T==r ->
     if is_list(L) ->
             call({munreg, T, l, existing(T,l,L)});
        true ->
@@ -1259,9 +1280,9 @@ munreg1(_, _, _) ->
     ?THROW_GPROC_ERROR(badarg).
 
 existing(T,Scope,L) ->
-    Keys = if T==p; T==c ->
+    Keys = if T==p; T==c; T==r ->
                    [{{T,Scope,K}, self()} || K <- L];
-              T==a; T==n ->
+              T==a; T==n; T==rc ->
                    [{{T,Scope,K}, T} || K <- L]
            end,
     _ = [case ets:member(?TAB, K) of
@@ -1828,18 +1849,19 @@ lookup_values({T,_,_} = Key) ->
 -spec update_counter(key(), increment()) -> integer() | [integer()].
 update_counter(Key, Incr) ->
     Pid = case Key of
-	      {n,_,_} -> n;
-	      {c,_,_} -> self()
-	  end,
+              {n,_,_} -> n;
+              {T,_,_} when T==c; T==r ->
+                  self()
+          end,
     ?CATCH_GPROC_ERROR(update_counter1(Key, Pid, Incr), [Key, Incr]).
 
 update_counter(Key, Pid, Incr) when is_pid(Pid);
 				    Pid == shared; Pid == n ->
     ?CATCH_GPROC_ERROR(update_counter1(Key, Pid, Incr), [Key, Pid, Incr]).
 
-update_counter1({T,l,_} = Key, Pid, Incr) when T==c; T==n ->
+update_counter1({T,l,_} = Key, Pid, Incr) when T==c; T==r; T==n ->
     gproc_lib:update_counter(Key, Incr, Pid);
-update_counter1({T,g,_} = Key, Pid, Incr) when T==c; T==n ->
+update_counter1({T,g,_} = Key, Pid, Incr) when T==c; T==r; T==n ->
     ?CHK_DIST,
     gproc_dist:update_counter(Key, Pid, Incr);
 update_counter1(_, _, _) ->
@@ -2302,15 +2324,15 @@ handle_call({reg_or_locate, {T,l,_} = Key, Val, P}, _, S) ->
 	    {reply, {OtherPid, OtherValue}, S}
     end;
 handle_call({monitor, {T,l,_} = Key, Pid, Type}, _From, S)
-  when T==n; T==a ->
+  when T==n; T==a; T==rc ->
     Ref = make_ref(),
     Lookup = ets:lookup(?TAB, {Key, T}),
     IsRegged = is_regged(Lookup),
     _ = case {IsRegged, Type} of
-	    {false, info} ->
-		Pid ! {gproc, unreg, Ref, Key};
+            {false, info} ->
+                Pid ! {gproc, unreg, Ref, Key};
             {false, follow} ->
-		Pid ! {gproc, unreg, Ref, Key},
+                Pid ! {gproc, unreg, Ref, Key},
                 _ = gproc_lib:ensure_monitor(Pid, l),
                 case Lookup of
                     [{K, Waiters}] ->
@@ -2326,19 +2348,19 @@ handle_call({monitor, {T,l,_} = Key, Pid, Type}, _From, S)
                 true = gproc_lib:insert_reg(Key, undefined, Pid, l, Evt),
                 Pid ! {gproc, Evt, Ref, Key},
                 _ = gproc_lib:ensure_monitor(Pid, l);
-	    {true, _} ->
+            {true, _} ->
                 [{_, RegPid, _}] = Lookup,
                 _ = gproc_lib:ensure_monitor(Pid, l),
-		case ets:lookup(?TAB, {RegPid, Key}) of
-		    [{K,r}] ->
-			ets:insert(?TAB, {K, [{monitor, [{Pid,Ref,Type}]}]}),
+                case ets:lookup(?TAB, {RegPid, Key}) of
+                    [{K,r}] ->
+                        ets:insert(?TAB, {K, [{monitor, [{Pid,Ref,Type}]}]}),
                         ets:insert_new(?TAB, {{Pid,Key}, []});
-		    [{K, Opts}] ->
-			ets:insert(?TAB, {K, gproc_lib:add_monitor(
+                    [{K, Opts}] ->
+                        ets:insert(?TAB, {K, gproc_lib:add_monitor(
                                                Opts, Pid, Ref, Type)}),
                         ets:insert_new(?TAB, {{Pid,Key}, []})
-		end
-	end,
+                end
+        end,
     {reply, Ref, S};
 handle_call({demonitor, {T,l,_} = Key, Ref, Pid}, _From, S)
   when T==n; T==a; T==rc ->
@@ -2910,7 +2932,7 @@ scope(S) when S==l; S==g -> S.
 
 type('_')   -> '_';
 type(all)   -> '_';
-type(T) when T==n; T==p; T==c; T==a -> T;
+type(T) when T==n; T==p; T==c; T==a; T==r; T==rc -> T;
 type(names) -> n;
 type(props) -> p;
 type(resources) -> r;
@@ -3084,24 +3106,24 @@ remove_dead(true, Objs) ->
 %% a test case that verifies the difference between having the option and not.
 qlc_lookup_pid(Pid, Scope, Check) ->
     case Check andalso ?PID_IS_DEAD(Pid) of
-	true ->
-	    [];
-	false ->
-	    Found =
-		ets:select(?TAB, [{{{Pid, rev_keypat(Scope)}, '_'},
-				   [], ['$_']}]),
-	    lists:flatmap(
-	      fun({{_,{T,_,_}=K}, _}) ->
-		      K2 = if T==n orelse T==a -> T;
-			      true -> Pid
-			   end,
-		      case ets:lookup(?TAB, {K,K2}) of
-			  [{{Key,_},_,Value}] ->
-			      [{Key, Pid, Value}];
-			  [] ->
-			      []
-		      end
-	      end, Found)
+        true ->
+            [];
+        false ->
+            Found =
+                ets:select(?TAB, [{{{Pid, rev_keypat(Scope)}, '_'},
+                                   [], ['$_']}]),
+            lists:flatmap(
+              fun({{_,{T,_,_}=K}, _}) ->
+                      K2 = if T==n orelse T==a orelse T==rc -> T;
+                              true -> Pid
+                           end,
+                      case ets:lookup(?TAB, {K,K2}) of
+                          [{{Key,_},_,Value}] ->
+                              [{Key, Pid, Value}];
+                          [] ->
+                              []
+                      end
+              end, Found)
     end.
 
 

+ 50 - 31
src/gproc_dist.erl

@@ -233,7 +233,8 @@ give_away({_,g,_} = Key, To) ->
 
 
 update_counter({T,g,_} = Key, Pid, Incr) when is_integer(Incr), T==c;
-					      is_integer(Incr), T==n ->
+                                              is_integer(Incr), T==r;
+                                              is_integer(Incr), T==n ->
     leader_call({update_counter, Key, Incr, Pid});
 update_counter(_, _, _) ->
     ?THROW_GPROC_ERROR(badarg).
@@ -518,14 +519,15 @@ handle_leader_call({reg_or_locate, {n,g,_} = K, Value, P},
     end;
 handle_leader_call({update_counter, {T,g,_Ctr} = Key, Incr, Pid}, _From, S, _E)
   when is_integer(Incr), T==c;
+       is_integer(Incr), T==r;
        is_integer(Incr), T==n ->
     try New = ets:update_counter(?TAB, {Key, Pid}, {3,Incr}),
-	 RealPid = case Pid of
-		       n -> ets:lookup_element(?TAB, {Key,Pid}, 2);
-		       shared -> shared;
-		       P when is_pid(P) -> P
-		   end,
-	 Vals = [{{Key,Pid},RealPid,New} | update_aggr_counter(Key, Incr)],
+         RealPid = case Pid of
+                       n -> ets:lookup_element(?TAB, {Key,Pid}, 2);
+                       shared -> shared;
+                       P when is_pid(P) -> P
+                   end,
+         Vals = [{{Key,Pid},RealPid,New} | update_aggr_counter(Key, Incr)],
         {reply, New, [{insert, Vals}], S}
     catch
         error:_ ->
@@ -1012,13 +1014,15 @@ surrendered_1(Globs) ->
 batch_update_counters(Cs) ->
     batch_update_counters(Cs, [], []).
 
-batch_update_counters([{{c,g,_} = Key, Pid, Incr}|T], Returns, Updates) ->
+batch_update_counters([{{T,g,_} = Key, Pid, Incr}|Cs], Returns, Updates)
+  when T==c; T==n; T==r ->
     case update_counter_g(Key, Incr, Pid) of
-	[{_,_,_} = A, {_, _, V} = C] ->
-	    batch_update_counters(T, [{Key,Pid,V}|Returns], add_object(
-							      A, add_object(C, Updates)));
-	[{_, _, V} = C] ->
-	    batch_update_counters(T, [{Key,Pid,V}|Returns], add_object(C, Updates))
+        [{_,_,_} = A, {_, _, V} = C] ->
+            batch_update_counters(Cs, [{Key,Pid,V}|Returns],
+                                  add_object(A, add_object(C, Updates)));
+        [{_, _, V} = C] ->
+            batch_update_counters(
+              Cs, [{Key,Pid,V}|Returns], add_object(C, Updates))
     end;
 batch_update_counters([], Returns, Updates) ->
     {lists:reverse(Returns), Updates}.
@@ -1033,22 +1037,37 @@ add_object(Obj, []) ->
 
 
 
-update_counter_g({c,g,_} = Key, Incr, Pid) when is_integer(Incr) ->
-    Res = ets:update_counter(?TAB, {Key, Pid}, {3,Incr}),
-    update_aggr_counter(Key, Incr, [{{Key,Pid},Pid,Res}]);
-update_counter_g({c,g,_} = Key, {Incr, Threshold, SetValue}, Pid)
-  when is_integer(Incr), is_integer(Threshold), is_integer(SetValue) ->
-    [Prev, New] = ets:update_counter(?TAB, {Key, Pid},
-				     [{3, 0}, {3, Incr, Threshold, SetValue}]),
-    update_aggr_counter(Key, New - Prev, [{{Key,Pid},Pid,New}]);
-update_counter_g({c,g,_} = Key, Ops, Pid) when is_list(Ops) ->
-    case ets:update_counter(?TAB, {Key, Pid},
-			    [{3, 0} | expand_ops(Ops)]) of
-	[_] ->
-	    [];
-	[Prev | Rest] ->
-	    [New | _] = lists:reverse(Rest),
-	    update_aggr_counter(Key, New - Prev, [{Key, Pid, Rest}])
+update_counter_g({T,g,_} = Key, Incr, Pid) when is_integer(Incr), T==c;
+                                                is_integer(Incr), T==r;
+                                                is_integer(Incr), T==n ->
+    R = if T==n -> T;
+           true -> Pid
+        end,
+    Res = ets:update_counter(?TAB, {Key, R}, {3,Incr}),
+    update_aggr_counter(Key, Incr, [{{Key,R},Pid,Res}]);
+update_counter_g({T,g,_} = Key, {Incr, Threshold, SetValue}, Pid)
+  when is_integer(Incr), is_integer(Threshold), is_integer(SetValue), T==c;
+       is_integer(Incr), is_integer(Threshold), is_integer(SetValue), T==r;
+       is_integer(Incr), is_integer(Threshold), is_integer(SetValue), T==n ->
+    R = if T==n -> T;
+           true -> Pid
+        end,
+    [Prev, New] = ets:update_counter(?TAB, {Key, R},
+                                     [{3, 0}, {3, Incr, Threshold, SetValue}]),
+    update_aggr_counter(Key, New - Prev, [{{Key,R},Pid,New}]);
+update_counter_g({T,g,_} = Key, Ops, Pid) when is_list(Ops), T==c;
+                                               is_list(Ops), T==r;
+                                               is_list(Ops), T==n ->
+    R = if T==n -> T;
+           true -> Pid
+        end,
+    case ets:update_counter(?TAB, {Key, R},
+                            [{3, 0} | expand_ops(Ops)]) of
+        [_] ->
+            [];
+        [Prev | Rest] ->
+            [New | _] = lists:reverse(Rest),
+            update_aggr_counter(Key, New - Prev, [{{Key,R}, Pid, Rest}])
     end;
 update_counter_g(_, _, _) ->
     ?THROW_GPROC_ERROR(badarg).
@@ -1064,11 +1083,11 @@ expand_ops([]) ->
 expand_ops(_) ->
     ?THROW_GPROC_ERROR(badarg).
 
-update_aggr_counter({n,_,_}, _) ->
-    [];
 update_aggr_counter(Key, Incr) ->
     update_aggr_counter(Key, Incr, []).
 
+update_aggr_counter({T,g,_}, _Incr, Acc) when T==n; T==r ->
+    Acc;
 update_aggr_counter({c,g,Ctr}, Incr, Acc) ->
     Key = {{a,g,Ctr},a},
     case ets:lookup(?TAB, Key) of

+ 21 - 19
src/gproc_lib.erl

@@ -46,7 +46,7 @@
          update_aggr_counter/3,
          update_counter/3,
          decrement_resource_count/2,
-	   valid_opts/2,
+         valid_opts/2,
          valid_key/1]).
 
 -export([dbg/1]).
@@ -529,40 +529,42 @@ do_set_counter_value({_,C,N} = Key, Value, Pid) ->
     Res.
 
 update_counter({T,l,Ctr} = Key, Incr, Pid) when is_integer(Incr), T==c;
-						is_integer(Incr), T==n ->
+                                                is_integer(Incr), T==r;
+                                                is_integer(Incr), T==n ->
     Res = ets:update_counter(?TAB, {Key, Pid}, {3,Incr}),
     if T==c ->
-	    update_aggr_counter(l, Ctr, Incr);
+            update_aggr_counter(l, Ctr, Incr);
        true ->
-	    ok
+            ok
     end,
     Res;
 update_counter({T,l,Ctr} = Key, {Incr, Threshold, SetValue}, Pid)
   when is_integer(Incr), is_integer(Threshold), is_integer(SetValue), T==c;
+       is_integer(Incr), is_integer(Threshold), is_integer(SetValue), T==r;
        is_integer(Incr), is_integer(Threshold), is_integer(SetValue), T==n ->
     [Prev, New] = ets:update_counter(?TAB, {Key, Pid},
-				     [{3, 0}, {3, Incr, Threshold, SetValue}]),
+                                     [{3, 0}, {3, Incr, Threshold, SetValue}]),
     if T==c ->
-	    update_aggr_counter(l, Ctr, New - Prev);
+            update_aggr_counter(l, Ctr, New - Prev);
        true ->
-	    ok
+            ok
     end,
     New;
 update_counter({T,l,Ctr} = Key, Ops, Pid) when is_list(Ops), T==c;
                                                is_list(Ops), T==r;
-					       is_list(Ops), T==n ->
+                                               is_list(Ops), T==n ->
     case ets:update_counter(?TAB, {Key, Pid},
-			    [{3, 0} | expand_ops(Ops)]) of
-	[_] ->
-	    [];
-	[Prev | Rest] ->
-	    [New | _] = lists:reverse(Rest),
-	    if T==c ->
-		    update_aggr_counter(l, Ctr, New - Prev);
-	       true ->
-		    ok
-	    end,
-	    Rest
+                            [{3, 0} | expand_ops(Ops)]) of
+        [_] ->
+            [];
+        [Prev | Rest] ->
+            [New | _] = lists:reverse(Rest),
+            if T==c ->
+                    update_aggr_counter(l, Ctr, New - Prev);
+               true ->
+                    ok
+            end,
+            Rest
     end;
 update_counter(_, _, _) ->
     ?THROW_GPROC_ERROR(badarg).

+ 59 - 14
test/gproc_dist_tests.erl

@@ -70,6 +70,8 @@ basic_tests(Ns) ->
      ?f(t_simple_ensure_other(Ns)),
      ?f(t_simple_reg_or_locate(Ns)),
      ?f(t_simple_counter(Ns)),
+     ?f(t_simple_r_counter(Ns)),
+     ?f(t_simple_n_counter(Ns)),
      ?f(t_aggr_counter(Ns)),
      ?f(t_awaited_aggr_counter(Ns)),
      ?f(t_simple_resource_count(Ns)),
@@ -78,6 +80,8 @@ basic_tests(Ns) ->
      ?f(t_awaited_resource_count(Ns)),
      ?f(t_resource_count_on_zero(Ns)),
      ?f(t_update_counters(Ns)),
+     ?f(t_update_r_counters(Ns)),
+     ?f(t_update_n_counters(Ns)),
      ?f(t_shared_counter(Ns)),
      ?f(t_prop(Ns)),
      ?f(t_mreg(Ns)),
@@ -216,6 +220,22 @@ t_simple_counter([H|_] = Ns) ->
     ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 5)),
     ?assertMatch(ok, t_call(P, die)).
 
+t_simple_r_counter([H|_] = Ns) ->
+    Ctr = ?T_RESOURCE,
+    P = t_spawn_reg(H, Ctr, 3),
+    ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 3)),
+    ?assertMatch(5, t_call(P, {apply, gproc, update_counter, [Ctr, 2]})),
+    ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 5)),
+    ?assertMatch(ok, t_call(P, die)).
+
+t_simple_n_counter([H|_] = Ns) ->
+    Ctr = ?T_NAME,
+    P = t_spawn_reg(H, Ctr, 3),
+    ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 3)),
+    ?assertMatch(5, t_call(P, {apply, gproc, update_counter, [Ctr, 2]})),
+    ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 5)),
+    ?assertMatch(ok, t_call(P, die)).
+
 t_shared_counter([H|_] = Ns) ->
     Ctr = ?T_COUNTER,
     P = t_spawn_reg_shared(H, Ctr, 3),
@@ -319,7 +339,6 @@ t_wild_key_in_resource([H1|_]) ->
     ?assertError({'DOWN', _, {badarg, _}},
                  t_call(P2, {apply, gproc, mreg, [r, g, [{Rw, 1}]]})).
 
-
 t_awaited_resource_count([H1,H2|_] = Ns) ->
     {r,g,Nm} = R = ?T_RESOURCE,
     RC = {rc,g,Nm},
@@ -368,29 +387,55 @@ t_resource_count_on_zero([H1,H2|_] = Ns) ->
     ?assertMatch(ok, t_call(Pp, die)),
     ?assertMatch(ok, t_call(Prc, die)).
 
-t_update_counters([H1,H2|_] = Ns) ->
-    {c,g,N1} = C1 = ?T_COUNTER,
-    A1 = {a,g,N1},
+t_update_counters(Ns) ->
+    C1 = ?T_COUNTER,
     C2 = ?T_COUNTER,
+    t_update_counters(C1, C1, C2, Ns).
+
+t_update_r_counters(Ns) ->
+    C1 = ?T_RESOURCE,
+    C2 = ?T_RESOURCE,
+    t_update_counters(C1, C1, C2, Ns).
+
+t_update_n_counters(Ns) ->
+    C1 = ?T_NAME,
+    C2 = ?T_NAME,
+    C3 = ?T_NAME,
+    t_update_counters(C1, C2, C3, Ns).
+
+t_update_counters(C1, C12, C2, [H1,H2|_] = Ns) ->
+    {T,g,N1} = C1,
+    A1 = {a,g,N1},
     P1 = t_spawn_reg(H1, C1, 2),
-    P12 = t_spawn_reg(H2, C1, 2),
+    P12 = t_spawn_reg(H2, C12, 2),
     P2 = t_spawn_reg(H2, C2, 1),
-    Pa1 = t_spawn_reg(H2, A1),
+    Pa1 = if T==c -> t_spawn_reg(H2, A1);
+             true -> undefined
+          end,
     ?assertMatch(ok, t_read_everywhere(C1, P1, Ns, 2)),
-    ?assertMatch(ok, t_read_everywhere(C1, P12, Ns, 2)),
+    ?assertMatch(ok, t_read_everywhere(C12, P12, Ns, 2)),
     ?assertMatch(ok, t_read_everywhere(C2, P2, Ns, 1)),
-    ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 4)),
+    if T==c -> ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 4));
+       true -> ok
+    end,
     ?assertMatch([{C1,P1, 3},
-		  {C1,P12,4},
-		  {C2,P2, 0}], t_call(P1, {apply, gproc, update_counters,
-					   [g, [{C1,P1,1},{C1,P12,2},{C2,P2,{-2,0,0}}]]})),
+                  {C12,P12,4},
+                  {C2,P2, 0}], t_call(P1, {apply, gproc, update_counters,
+                                           [g, [ {C1,P1,1}
+                                               , {C12,P12,2}
+                                               , {C2,P2,{-2,0,0}} ]]})),
     ?assertMatch(ok, t_read_everywhere(C1, P1, Ns, 3)),
-    ?assertMatch(ok, t_read_everywhere(C1, P12, Ns, 4)),
+    ?assertMatch(ok, t_read_everywhere(C12, P12, Ns, 4)),
     ?assertMatch(ok, t_read_everywhere(C2, P2, Ns, 0)),
-    ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 7)),
+    if T==c -> ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 7));
+       true -> ok
+    end,
     ?assertMatch(ok, t_call(P1, die)),
     ?assertMatch(ok, t_call(P12, die)),
-    ?assertMatch(ok, t_call(P2, die)).
+    ?assertMatch(ok, t_call(P2, die)),
+    if T==c -> ?assertMatch(ok, t_call(Pa1, die));
+       true -> ok
+    end.
 
 t_prop([H1,H2|_] = Ns) ->
     {p, g, _} = P = ?T_PROP,

+ 15 - 0
test/gproc_tests.erl

@@ -108,6 +108,10 @@ reg_test_() ->
       , ?_test(t_is_clean())
       , {spawn, ?_test(?debugVal(t_update_counters()))}
       , ?_test(t_is_clean())
+      , {spawn, ?_test(?debugVal(t_update_r_counter()))}
+      , ?_test(t_is_clean())
+      , {spawn, ?_test(?debugVal(t_update_n_counter()))}
+      , ?_test(t_is_clean())
       , {spawn, ?_test(?debugVal(t_simple_prop()))}
       , ?_test(t_is_clean())
       , {spawn, ?_test(?debugVal(t_await()))}
@@ -446,6 +450,17 @@ t_update_counters() ->
     end,
     ?assert(gproc:get_value({a,l,c1}) =:= 7).
 
+t_update_r_counter() ->
+    K = {r,l,r1},
+    ?assert(gproc:reg(K, 3) =:= true),
+    ?assertEqual(5, gproc:update_counter(K, 2)),
+    ?assert(gproc:get_value(K) =:= 5).
+
+t_update_n_counter() ->
+    K = {n,l,n1},
+    ?assert(gproc:reg(K, 3) =:= true),
+    ?assertEqual(5, gproc:update_counter(K, 2)),
+    ?assert(gproc:get_value(K) =:= 5).
 
 t_simple_prop() ->
     ?assert(gproc:reg({p,l,prop}) =:= true),