[erlang-questions] Complex gproc queries

Ulf Wiger <>
Sat Apr 3 16:34:19 CEST 2010


Pablo Platt wrote:
> Thank you very much for the detailed answer.
> gproc is super powerful with QLC.

Thanks. Yes, I think so too.

Now that you seem satisfied with the answer, I copy the list
again. I didn't want to litter it with my attempts at
understanding what you were really after.

BR,
Ulf W


> 
> ------------------------------------------------------------------------
> *From:* Ulf Wiger <>
> *To:* Pablo Platt <>
> *Sent:* Sat, April 3, 2010 3:24:01 PM
> *Subject:* Re: [erlang-questions] Complex gproc queries
> 
> Pablo Platt wrote:
>  > I think that this assumes that users in the roster are online.
>  >  > Wouldn't this just be [gproc:send({p,l,Id}, Msg) || Id <- Roster] then
>  > If some users are not online and the roster is big I'll need to make 
> a lot of queries every time.
> 
> Ok, so let's look at QLC. In this first example, I still assume that
> you have a list of Ids to check in, so it's pretty much doing the
> same thing as the snippet above:
> 
> 2> spawn(fun() -> gproc:reg({p,l,foo}), receive die -> die end end).
> <0.41.0>
> 3> spawn(fun() -> gproc:reg({p,l,foo}), receive die -> die end end).
> <0.43.0>
> 4> spawn(fun() -> gproc:reg({p,l,foo}), receive die -> die end end).
> <0.45.0>
> 5> spawn(fun() -> gproc:reg({p,l,foo}), receive die -> die end end).
> <0.47.0>
> 6> spawn(fun() -> gproc:reg({p,l,bar}), receive die -> die end end).
> <0.49.0>
> 7> spawn(fun() -> gproc:reg({p,l,bar}), receive die -> die end end).
> <0.51.0>
> 8> spawn(fun() -> gproc:reg({p,l,bar}), receive die -> die end end).
> <0.53.0>
> 9> Q1 = qlc:q([P || {{p,l,X},P,_} <- gproc:table(props),
>               lists:member(X, [foo])])).
> {qlc_handle,{qlc_lc,#Fun<erl_eval.20.67289768>,
>                     {qlc_opt,false,false,-1,any,[],any,524288,allowed}}}
> 10> qlc:e(Q1).
> [<0.41.0>,<0.43.0>,<0.45.0>,<0.47.0>]
> 
> Now, let's assume you have a mnesia table that makes up the roster.
> I don't know the structure of this table, but one possible way to
> represent it would be to have it as an ordered_set disc_copy,
> and then use the key {Roster, UserId}.
> 
> 11> mnesia:create_schema([node()]).
> ok
> 12> mnesia:start().
> ok
> 13> mnesia:create_table(roster,[{ram_copies,[node()]},{type,ordered_set}]).
> {atomic,ok}
> 14> mnesia:dirty_write({roster,{r1,foo},[]}).
> ok
> 15> catch qlc:e(qlc:q([P || {{p,l,X},P,_} <- gproc:table(props), 
> ets:member(roster,{r1,X})])).
> [<0.41.0>,<0.43.0>,<0.45.0>,<0.47.0>]
> 
> I used ets:member/2 here, which would only work if executed on a
> node that actually has a copy in RAM of the roster table, and
> it doesn't respect any mnesia-level locks. You could write your
> own function, e.g. is_member(R, UId) that does a mnesia lookup,
> and then run the query inside a transaction...
> 
> You can make this into a more complex QLC query, but I'm not
> certain what the performance would be:
> 
> 16> rd(roster,{key,value}).  % define the record in the shell            
>                       roster
> 17> Q2 = qlc:q([P ||
>             {{p,l,X},P,_} <- gproc:table(props),
>             #roster{key={r1,X1}} <- mnesia:table(roster),
>             X==X1]).
> {qlc_handle,{qlc_lc,#Fun<erl_eval.20.67289768>,
>                     {qlc_opt,false,false,-1,any,[],any,524288,allowed}}}
> 18> mnesia:activity(transaction, fun() -> qlc:e(Q2) end).
> [<0.41.0>,<0.43.0>,<0.45.0>,<0.47.0>]
> 
> The above is rather trivially generalized to work with rosters other
> than 'r1', of course.
> 
> Hope this was more helpful.
> 
> BR,
> Ulf W
> 
>  > What I thought doing is to first query for a list of users that are 
> both in the roster and online
>  > and only then send them a message.
>  >
>  > ------------------------------------------------------------------------
>  > *From:* Ulf Wiger < 
> <mailto:>>
>  > *To:* Pablo Platt < <mailto:>>
>  > *Sent:* Sat, April 3, 2010 1:52:36 AM
>  > *Subject:* Re: [erlang-questions] Complex gproc queries
>  >
>  >
>  > Ah, I thought you used gproc to keep up with the roster
>  > as well. :)
>  >
>  > Wouldn't this just be [gproc:send({p,l,Id}, Msg) || Id <- Roster] then?
>  >
>  > Or am I missing something again? If so, you may respond to me directly.
>  >
>  > BTW, I have merged minor changes from Hans Svensson and fixed
>  > the EQC suite. New commit, in other words.
>  >
>  > BR,
>  > Ulf W
>  >
>  > Pablo Platt wrote:
>  >  >  I should have said that Roster is a list with the contact list IDs
>  >  > Roster = [id1, id2, id3...]
>  >  > each user have a different list.
>  >  > I need to send a message to all the the users in the list that are 
> online.
>  >  >
>  >  > Thanks
>  >  >
>  >  >
>  >  > 
> ------------------------------------------------------------------------
>  >  > *From:* Ulf Wiger < 
> <mailto:> 
> <mailto: 
> <mailto:>>>
>  >  > *To:* Pablo Platt < 
> <mailto:> <mailto: 
> <mailto:>>>
>  >  > *Cc:*  
> <mailto:> <mailto: 
> <mailto:>>
>  >  > *Sent:* Fri, April 2, 2010 7:37:25 PM
>  >  > *Subject:* Re: [erlang-questions] Complex gproc queries
>  >  >
>  >  > Pablo Platt wrote:
>  >  >  > Hi,
>  >  >  >
>  >  >  > I'm building a simple chat server and using gproc to keep track 
> of online users and the process for each user session.
>  >  >  >
>  >  >  > Basically, each online user has a process that register a 
> unique session id and non unique user id (same user can have several 
> clients):
>  >  >  > gproc:add_local_name(SessionId)
>  >  >  > gproc:add_local_property(UserId, undefined)
>  >  >  >
>  >  >  > When a user change his presence(online/busy/offline) I need to 
> inform all the users on his roster.
>  >  >  > After I retrieved the roster from the db, how can I select all 
> the processes with UserId that is a part of the roster?
>  >  >  > Rusty Klupaus's blog about gproc note that gproc:select support 
> QLC but I don't understand how to do it.
>  >  >>
>  >>
>> 
> http://rklophaus.com/blog/2009/9/16/gproc-erlang-global-process-registry.html
>  >  >  >
>  >  >  > Thanks
>  >  >
>  >  > Not sure if you need any complex queries for that.
>  >  > If all members of a roster have a property {p,l,Roster},
>  >  > then all it should take is:
>  >  >
>  >  > gproc:send({p,l,Roster}, Msg)
>  >  >
>  >  > If you want to e.g. exclude the sender, you could use:
>  >  >
>  >  > [P ! Msg || P <- gproc:lookup_pids({p,l,Roster}) -- [self()]]
>  >  >
>  >  > Disclaimer: When verifying this, I found that gproc:send/2 was
>  >  > broken for properties. I fixed it in the last commit, 1 minute ago.
>  >  >
>  >  > The commit also changes anther bug: aggregated counters had to
>  >  > have an integer value when created. This doesn't make sense, since
>  >  > the value is derived; therefore the only sensible value is 
> 'undefined',
>  >  > which is what you get if you call gproc:reg({a,l,AggrCounter}).
>  >  >
>  >  > Unfortunately, the commit broke the QuickCheck suite... I had forgot
>  >  > that I started writing a test for gproc:await/1 at the SF Erlang
>  >  > factory, didn't finish it. Oh well, if anyone is really hurt by
>  >  > this condition, let me know. (Hans, I haven't merged your changes
>  >  > yet).
>  >  >
>  >  > BR,
>  >  > Ulf W
>  >  > -- Ulf Wiger
>  >  > CTO, Erlang Solutions Ltd, formerly Erlang Training & Consulting Ltd
>> >  http://www.erlang-solutions.com
>  >  > ---------------------------------------------------
>  >  >
>  >  > ---------------------------------------------------
>  >  >
>  >  > WE'VE CHANGED NAMES!
>  >  >
>  >  > Since January 1st 2010 Erlang Training and Consulting Ltd. has 
> become ERLANG SOLUTIONS LTD.
>  >  >
>  >  > www.erlang-solutions.com <http://www.erlang-solutions.com> 
> <http://www.erlang-solutions.com> <http://www.erlang-solutions.com>
>  >  >
>  >  >
>  >
>  >
>  > -- Ulf Wiger
>  > CTO, Erlang Solutions Ltd, formerly Erlang Training & Consulting Ltd
>  > http://www.erlang-solutions.com
>  >
> 
> 
> -- Ulf Wiger
> CTO, Erlang Solutions Ltd, formerly Erlang Training & Consulting Ltd
> http://www.erlang-solutions.com
> 


-- 
Ulf Wiger
CTO, Erlang Solutions Ltd, formerly Erlang Training & Consulting Ltd
http://www.erlang-solutions.com


More information about the erlang-questions mailing list