[erlang-questions] Complex gproc queries
Ulf Wiger
ulf.wiger@REDACTED
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 <ulf.wiger@REDACTED>
> *To:* Pablo Platt <pablo.platt@REDACTED>
> *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 <ulf.wiger@REDACTED
> <mailto:ulf.wiger@REDACTED>>
> > *To:* Pablo Platt <pablo.platt@REDACTED <mailto:pablo.platt@REDACTED>>
> > *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 <ulf.wiger@REDACTED
> <mailto:ulf.wiger@REDACTED>
> <mailto:ulf.wiger@REDACTED
> <mailto:ulf.wiger@REDACTED>>>
> > > *To:* Pablo Platt <pablo.platt@REDACTED
> <mailto:pablo.platt@REDACTED> <mailto:pablo.platt@REDACTED
> <mailto:pablo.platt@REDACTED>>>
> > > *Cc:* erlang-questions@REDACTED
> <mailto:erlang-questions@REDACTED> <mailto:erlang-questions@REDACTED
> <mailto:erlang-questions@REDACTED>>
> > > *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