gproc.erl 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. %% ``The contents of this file are subject to the Erlang Public License,
  2. %% Version 1.1, (the "License"); you may not use this file except in
  3. %% compliance with the License. You should have received a copy of the
  4. %% Erlang Public License along with this software. If not, it can be
  5. %% retrieved via the world wide web at http://www.erlang.org/.
  6. %%
  7. %% Software distributed under the License is distributed on an "AS IS"
  8. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  9. %% the License for the specific language governing rights and limitations
  10. %% under the License.
  11. %%
  12. %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  13. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  14. %% AB. All Rights Reserved.''
  15. %%
  16. %% @author Ulf Wiger <ulf.wiger@erlang-consulting.com>
  17. %%
  18. %% @doc Extended process registry
  19. %% <p>This module implements an extended process registry</p>
  20. %% <p>For a detailed description, see
  21. %% <a href="erlang07-wiger.pdf">erlang07-wiger.pdf</a>.</p>
  22. %%
  23. %% @type type() = n | p | c | a. n = name; p = property; c = counter;
  24. %% a = aggregate_counter
  25. %% @type scope() = l | g. l = local registration; g = global registration
  26. %% @type context() = {scope(), type()} | type(). Local scope is the default
  27. %% @type sel_type() = n | p | c | a |
  28. %% names | props | counters | aggr_counters.
  29. %% @type headpat() = {keypat(),pidpat(),ValPat}.
  30. %% @type keypat() = {sel_type() | sel_var(),
  31. %% l | g | sel_var(),
  32. %% any()}.
  33. %% @type pidpat() = pid() | sel_var().
  34. %% sel_var() = DollarVar | '_'.
  35. %% @type sel_pattern() = [{headpat(), Guards, Prod}].
  36. %% @type key() = {type(), scope(), any()}
  37. %% @end
  38. -module(gproc).
  39. -behaviour(gen_server).
  40. -export([start_link/0,
  41. reg/1, reg/2, unreg/1,
  42. mreg/3,
  43. set_value/2,
  44. get_value/1,
  45. where/1,
  46. lookup_pid/1,
  47. lookup_pids/1,
  48. lookup_values/1,
  49. update_counter/2,
  50. send/2,
  51. info/1, info/2,
  52. select/1, select/2, select/3,
  53. first/1,
  54. next/2,
  55. prev/2,
  56. last/1,
  57. table/1, table/2]).
  58. %% Convenience functions
  59. -export([add_local_name/1,
  60. add_global_name/1,
  61. add_local_property/2,
  62. add_global_property/2,
  63. add_local_counter/2,
  64. add_global_counter/2,
  65. add_local_aggr_counter/1,
  66. add_global_aggr_counter/1,
  67. lookup_local_name/1,
  68. lookup_global_name/1,
  69. lookup_local_properties/1,
  70. lookup_global_properties/1,
  71. lookup_local_counters/1,
  72. lookup_global_counters/1,
  73. lookup_local_aggr_counter/1,
  74. lookup_global_aggr_counter/1]).
  75. -export([default/1]).
  76. %%% internal exports
  77. -export([init/1,
  78. handle_cast/2,
  79. handle_call/3,
  80. handle_info/2,
  81. code_change/3,
  82. terminate/2]).
  83. -include("gproc.hrl").
  84. -define(SERVER, ?MODULE).
  85. %%-define(l, l(?LINE)). % when activated, calls a traceable empty function
  86. -define(l, ignore).
  87. -define(CHK_DIST,
  88. case whereis(gproc_dist) of
  89. undefined ->
  90. erlang:error(local_only);
  91. _ ->
  92. ok
  93. end).
  94. -record(state, {}).
  95. %% @spec () -> {ok, pid()}
  96. %%
  97. %% @doc Starts the gproc server.
  98. %%
  99. %% This function is intended to be called from gproc_sup, as part of
  100. %% starting the gproc application.
  101. %% @end
  102. start_link() ->
  103. create_tabs(),
  104. gen_server:start({local, ?SERVER}, ?MODULE, [], []).
  105. %% spec(Name::any()) -> true
  106. %%
  107. %% @doc Registers a local (unique) name. @equiv reg({n,l,Name})
  108. %% @end
  109. %%
  110. add_local_name(Name) -> reg({n,l,Name}, undefined).
  111. %% spec(Name::any()) -> true
  112. %%
  113. %% @doc Registers a global (unique) name. @equiv reg({n,g,Name})
  114. %% @end
  115. %%
  116. add_global_name(Name) -> reg({n,g,Name}, undefined).
  117. %% spec(Name::any(), Value::any()) -> true
  118. %%
  119. %% @doc Registers a local (non-unique) property. @equiv reg({p,l,Name},Value)
  120. %% @end
  121. %%
  122. add_local_property(Name , Value) -> reg({p,l,Name}, Value).
  123. %% spec(Name::any(), Value::any()) -> true
  124. %%
  125. %% @doc Registers a global (non-unique) property. @equiv reg({p,g,Name},Value)
  126. %% @end
  127. %%
  128. add_global_property(Name, Value) -> reg({p,g,Name}, Value).
  129. %% spec(Name::any(), Initial::integer()) -> true
  130. %%
  131. %% @doc Registers a local (non-unique) counter. @equiv reg({c,l,Name},Value)
  132. %% @end
  133. %%
  134. add_local_counter(Name, Initial) when is_integer(Initial) ->
  135. reg({c,l,Name}, Initial).
  136. %% spec(Name::any(), Initial::integer()) -> true
  137. %%
  138. %% @doc Registers a global (non-unique) counter. @equiv reg({c,g,Name},Value)
  139. %% @end
  140. %%
  141. add_global_counter(Name, Initial) when is_integer(Initial) ->
  142. reg({n,g,Name}, Initial).
  143. %% spec(Name::any()) -> true
  144. %%
  145. %% @doc Registers a local (unique) aggregated counter.
  146. %% @equiv reg({a,l,Name})
  147. %% @end
  148. %%
  149. add_local_aggr_counter(Name) -> reg({a,l,Name}).
  150. %% spec(Name::any()) -> true
  151. %%
  152. %% @doc Registers a global (unique) aggregated counter.
  153. %% @equiv reg({a,l,Name})
  154. %% @end
  155. %%
  156. add_global_aggr_counter(Name) -> reg({a,g,Name}).
  157. %% @spec (Name::any()) -> pid()
  158. %%
  159. %% @doc Lookup a local unique name. Fails if there is no such name.
  160. %% @equiv where({n,l,Name})
  161. %% @end
  162. %%
  163. lookup_local_name(Name) -> where({n,l,Name}).
  164. %% @spec (Name::any()) -> pid()
  165. %%
  166. %% @doc Lookup a global unique name. Fails if there is no such name.
  167. %% @equiv where({n,g,Name})
  168. %% @end
  169. %%
  170. lookup_global_name(Name) -> where({g,l,Name}).
  171. %% @spec (Name::any()) -> integer()
  172. %%
  173. %% @doc Lookup a local (unique) aggregated counter and returns its value.
  174. %% Fails if there is no such object.
  175. %% @equiv where({a,l,Name})
  176. %% @end
  177. %%
  178. lookup_local_aggr_counter(Name) -> lookup_value({a,l,Name}).
  179. %% @spec (Name::any()) -> integer()
  180. %%
  181. %% @doc Lookup a global (unique) aggregated counter and returns its value.
  182. %% Fails if there is no such object.
  183. %% @equiv where({a,g,Name})
  184. %% @end
  185. %%
  186. lookup_global_aggr_counter(Name) -> lookup_value({a,g,Name}).
  187. %% @spec (Property::any()) -> [{pid(), Value}]
  188. %%
  189. %% @doc Look up all local (non-unique) instances of a given Property.
  190. %% Returns a list of {Pid, Value} tuples for all matching objects.
  191. %% @equiv lookup_values({p, l, Property})
  192. %% @end
  193. %%
  194. lookup_local_properties(P) -> lookup_values({p,l,P}).
  195. %% @spec (Property::any()) -> [{pid(), Value}]
  196. %%
  197. %% @doc Look up all global (non-unique) instances of a given Property.
  198. %% Returns a list of {Pid, Value} tuples for all matching objects.
  199. %% @equiv lookup_values({p, g, Property})
  200. %% @end
  201. %%
  202. lookup_global_properties(P) -> lookup_values({p,g,P}).
  203. %% @spec (Counter::any()) -> [{pid(), Value::integer()}]
  204. %%
  205. %% @doc Look up all local (non-unique) instances of a given Counter.
  206. %% Returns a list of {Pid, Value} tuples for all matching objects.
  207. %% @equiv lookup_values({c, l, Counter})
  208. %% @end
  209. %%
  210. lookup_local_counters(P) -> lookup_values({c,l,P}).
  211. %% @spec (Counter::any()) -> [{pid(), Value::integer()}]
  212. %%
  213. %% @doc Look up all global (non-unique) instances of a given Counter.
  214. %% Returns a list of {Pid, Value} tuples for all matching objects.
  215. %% @equiv lookup_values({c, l, Counter})
  216. %% @end
  217. %%
  218. lookup_global_counters(P) -> lookup_values({c,g,P}).
  219. %% @spec reg(Key::key()) -> true
  220. %%
  221. %% @doc
  222. %% @equiv reg(Key, default(Key))
  223. %% @end
  224. reg(Key) ->
  225. reg(Key, default(Key)).
  226. default({T,_,_}) when T==c; T==a -> 0;
  227. default(_) -> undefined.
  228. %% @spec reg(Key::key(), Value) -> true
  229. %%
  230. %% @doc Register a name or property for the current process
  231. %%
  232. %%
  233. reg({_,g,_} = Key, Value) ->
  234. %% anything global
  235. ?CHK_DIST,
  236. gproc_dist:reg(Key, Value);
  237. reg({p,l,_} = Key, Value) ->
  238. local_reg(Key, Value);
  239. reg({T,l,_} = Key, Value) when T==n; T==c; T==a ->
  240. %% local names, counters and aggregated counters
  241. if is_integer(Value) ->
  242. call({reg, Key, Value});
  243. true ->
  244. erlang:error(badarg)
  245. end;
  246. reg(_, _) ->
  247. erlang:error(badarg).
  248. %% @spec mreg(type(), scope(), [{Key::any(), Value::any()}]) -> true
  249. %%
  250. %% @doc Register multiple {Key,Value} pairs of a given type and scope.
  251. %%
  252. %% This function is more efficient than calling {@link reg/2} repeatedly.
  253. %% @end
  254. mreg(T, g, KVL) ->
  255. ?CHK_DIST,
  256. gproc_dist:mreg(T, KVL);
  257. mreg(T, l, KVL) when T==a; T==n ->
  258. if is_list(KVL) ->
  259. call({mreg, T, l, KVL});
  260. true ->
  261. erlang:error(badarg)
  262. end;
  263. mreg(p, l, KVL) ->
  264. local_mreg(p, KVL);
  265. mreg(_, _, _) ->
  266. erlang:error(badarg).
  267. %% @spec (Key:: key()) -> true
  268. %%
  269. %% @doc Unregister a name or property.
  270. %% @end
  271. unreg(Key) ->
  272. case Key of
  273. {_, g, _} ->
  274. ?CHK_DIST,
  275. gproc_dist:unreg(Key);
  276. {T, l, _} when T == n;
  277. T == a -> call({unreg, Key});
  278. {_, l, _} ->
  279. case ets:member(?TAB, {Key,self()}) of
  280. true ->
  281. gproc_lib:remove_reg(Key, self());
  282. false ->
  283. erlang:error(badarg)
  284. end
  285. end.
  286. %% @spec (select_pattern()) -> list(sel_object())
  287. %% @doc
  288. %% @equiv select(all, Pat)
  289. %% @end
  290. select(Pat) ->
  291. select(all, Pat).
  292. %% @spec (Type::sel_type(), Pat::sel_pattern()) -> [{Key, Pid, Value}]
  293. %%
  294. %% @doc Perform a select operation on the process registry.
  295. %%
  296. %% The physical representation in the registry may differ from the above,
  297. %% but the select patterns are transformed appropriately.
  298. %% @end
  299. select(Type, Pat) ->
  300. ets:select(?TAB, pattern(Pat, Type)).
  301. %% @spec (Type::sel_type(), Pat::sel_patten(), Limit::integer()) ->
  302. %% [{Key, Pid, Value}]
  303. %% @doc Like {@link select/2} but returns Limit objects at a time.
  304. %%
  305. %% See [http://www.erlang.org/doc/man/ets.html#select-3].
  306. %% @end
  307. select(Type, Pat, Limit) ->
  308. ets:select(?TAB, pattern(Pat, Type), Limit).
  309. %%% Local properties can be registered in the local process, since
  310. %%% no other process can interfere.
  311. %%%
  312. local_reg(Key, Value) ->
  313. case gproc_lib:insert_reg(Key, Value, self(), l) of
  314. false -> erlang:error(badarg);
  315. true -> monitor_me()
  316. end.
  317. local_mreg(_, []) -> true;
  318. local_mreg(T, [_|_] = KVL) ->
  319. case gproc_lib:insert_many(T, l, KVL, self()) of
  320. false -> erlang:error(badarg);
  321. {true,_} -> monitor_me()
  322. end.
  323. %% @spec (Key :: key(), Value) -> true
  324. %% @doc Sets the value of the registeration entry given by Key
  325. %%
  326. %% Key is assumed to exist and belong to the calling process.
  327. %% If it doesn't, this function will exit.
  328. %%
  329. %% Value can be any term, unless the object is a counter, in which case
  330. %% it must be an integer.
  331. %% @end
  332. %%
  333. set_value({_,g,_} = Key, Value) ->
  334. ?CHK_DIST,
  335. gproc_dist:set_value(Key, Value);
  336. set_value({a,l,_} = Key, Value) when is_integer(Value) ->
  337. call({set, Key, Value});
  338. set_value({n,l,_} = Key, Value) ->
  339. %% we cannot do this locally, since we have to check that the object
  340. %% exists first - not an atomic update.
  341. call({set, Key, Value});
  342. set_value({p,l,_} = Key, Value) ->
  343. %% we _can_ to this locally, since there is no race condition - no
  344. %% other process can update our properties.
  345. case gproc_lib:do_set_value(Key, Value, self()) of
  346. true -> true;
  347. false ->
  348. erlang:error(badarg)
  349. end;
  350. set_value({c,l,_} = Key, Value) when is_integer(Value) ->
  351. gproc_lib:do_set_counter_value(Key, Value, self());
  352. set_value(_, _) ->
  353. erlang:error(badarg).
  354. %% @spec (Key) -> Value
  355. %% @doc Read the value stored with a key registered to the current process.
  356. %%
  357. %% If no such key is registered to the current process, this function exits.
  358. %% @end
  359. get_value(Key) ->
  360. get_value(Key, self()).
  361. get_value({T,_,_} = Key, Pid) when is_pid(Pid) ->
  362. if T==n orelse T==a ->
  363. case ets:lookup(?TAB, {Key, T}) of
  364. [{_, P, Value}] when P == Pid -> Value;
  365. _ -> erlang:error(badarg)
  366. end;
  367. true ->
  368. ets:lookup_element(?TAB, {Key, Pid}, 3)
  369. end;
  370. get_value(_, _) ->
  371. erlang:error(badarg).
  372. %% @spec (Key) -> Pid
  373. %% @doc Lookup the Pid stored with a key.
  374. %%
  375. lookup_pid({_T,_,_} = Key) ->
  376. case where(Key) of
  377. undefined -> erlang:error(badarg);
  378. P -> P
  379. end.
  380. lookup_value({T,_,_} = Key) ->
  381. if T==n orelse T==a ->
  382. ets:lookup_element(?TAB, {Key,T}, 3);
  383. true ->
  384. erlang:error(badarg)
  385. end.
  386. %% @spec (Key::key()) -> pid()
  387. %%
  388. %% @doc Returns the pid registered as Key
  389. %%
  390. %% The type of registration entry must be either name or aggregated counter.
  391. %% Otherwise this function will exit. Use {@link lookup_pids/1} in these
  392. %% cases.
  393. %% @end
  394. %%
  395. where({T,_,_}=Key) ->
  396. if T==n orelse T==a ->
  397. case ets:lookup(?TAB, {Key,T}) of
  398. [] ->
  399. undefined;
  400. [{_, P, _Value}] ->
  401. P
  402. end;
  403. true ->
  404. erlang:error(badarg)
  405. end.
  406. %% @spec (Key::key()) -> [pid()]
  407. %%
  408. %% @doc Returns a list of pids with the published key Key
  409. %%
  410. %% If the type of registration entry is either name or aggregated counter,
  411. %% this function will return either an empty list, or a list of one pid.
  412. %% For non-unique types, the return value can be a list of any length.
  413. %% @end
  414. %%
  415. lookup_pids({T,_,_} = Key) ->
  416. if T==n orelse T==a ->
  417. ets:select(?TAB, [{{{Key,T}, '$1', '_'},[],['$1']}]);
  418. true ->
  419. ets:select(?TAB, [{{{Key,'_'}, '$1', '_'},[],['$1']}])
  420. %%% true ->
  421. %%% erlang:error(badarg)
  422. end.
  423. %% @spec (Key::key()) -> [{pid(), Value}]
  424. %%
  425. %% @doc Retrieve the `{Pid,Value}' pairs corresponding to Key.
  426. %%
  427. %% Key refer to any type of registry object. If it refers to a unique
  428. %% object, the list will be of length 0 or 1. If it refers to a non-unique
  429. %% object, the return value can be a list of any length.
  430. %% @end
  431. %%
  432. lookup_values({T,_,_} = Key) ->
  433. if T==n orelse T==a ->
  434. ets:select(?TAB, [{{{Key,T}, '$1', '$2'},[],[{{'$1','$2'}}]}]);
  435. true ->
  436. ets:select(?TAB, [{{{Key,'_'}, '$1', '$2'},[],[{{'$1','$2'}}]}])
  437. end.
  438. %% @spec (Key::key(), Incr::integer()) -> integer()
  439. %%
  440. %% @doc Updates the counter registered as Key for the current process.
  441. %%
  442. %% This function works like ets:update_counter/3
  443. %% (see [http://www.erlang.org/doc/man/ets.html#update_counter-3]), but
  444. %% will fail if the type of object referred to by Key is not a counter.
  445. %% @end
  446. %%
  447. update_counter({c,l,_} = Key, Incr) when is_integer(Incr) ->
  448. gproc_lib:update_counter(Key, Incr, self());
  449. update_counter({c,g,_} = Key, Incr) when is_integer(Incr) ->
  450. ?CHK_DIST,
  451. gproc_dist:update_counter(Key, Incr);
  452. update_counter(_, _) ->
  453. erlang:error(badarg).
  454. %% @spec (Key::key(), Msg::any()) -> Msg
  455. %%
  456. %% @doc Sends a message to the process, or processes, corresponding to Key.
  457. %%
  458. %% If Key belongs to a unique object (name or aggregated counter), this
  459. %% function will send a message to the corresponding process, or fail if there
  460. %% is no such process. If Key is for a non-unique object type (counter or
  461. %% property), Msg will be send to all processes that have such an object.
  462. %% @end
  463. %%
  464. send({T,C,_} = Key, Msg) when C==l; C==g ->
  465. if T == n orelse T == a ->
  466. case ets:lookup(?TAB, {Key, T}) of
  467. [{_, Pid, _}] ->
  468. Pid ! Msg;
  469. [] ->
  470. erlang:error(badarg)
  471. end;
  472. T==p orelse T==c ->
  473. %% BUG - if the key part contains select wildcards, we may end up
  474. %% sending multiple messages to the same pid
  475. Head = {{Key,'$1'},'_'},
  476. Pids = ets:select(?TAB, [{Head,[],['$1']}]),
  477. lists:foreach(fun(Pid) ->
  478. Pid ! Msg
  479. end, Pids),
  480. Msg;
  481. true ->
  482. erlang:error(badarg)
  483. end;
  484. send(_, _) ->
  485. erlang:error(badarg).
  486. %% @spec (Type :: type()) -> key() | '$end_of_table'
  487. %%
  488. %% @doc Behaves as ets:first(Tab) for a given type of registration object.
  489. %%
  490. %% See [http://www.erlang.org/doc/man/ets.html#first-1].
  491. %% The registry behaves as an ordered_set table.
  492. %% @end
  493. %%
  494. first(Type) ->
  495. {HeadPat,_} = headpat(Type, '_', '_', '_'),
  496. case ets:select(?TAB, [{HeadPat,[],[{element,1,'$_'}]}], 1) of
  497. {[First], _} ->
  498. First;
  499. _ ->
  500. '$end_of_table'
  501. end.
  502. %% @spec (Context :: context()) -> key() | '$end_of_table'
  503. %%
  504. %% @doc Behaves as ets:last(Tab) for a given type of registration object.
  505. %%
  506. %% See [http://www.erlang.org/doc/man/ets.html#last-1].
  507. %% The registry behaves as an ordered_set table.
  508. %% @end
  509. %%
  510. last(Context) ->
  511. {S, T} = get_s_t(Context),
  512. S1 = if S == '_'; S == l -> m;
  513. S == g -> h
  514. end,
  515. Beyond = {{T,S1,[]},[]},
  516. step(ets:prev(?TAB, Beyond), S, T).
  517. %% @spec (Context::context(), Key::key()) -> key() | '$end_of_table'
  518. %%
  519. %% @doc Behaves as ets:next(Tab,Key) for a given type of registration object.
  520. %%
  521. %% See [http://www.erlang.org/doc/man/ets.html#next-2].
  522. %% The registry behaves as an ordered_set table.
  523. %% @end
  524. %%
  525. next(Context, K) ->
  526. {S,T} = get_s_t(Context),
  527. step(ets:next(?TAB,K), S, T).
  528. %% @spec (Context::context(), Key::key()) -> key() | '$end_of_table'
  529. %%
  530. %% @doc Behaves as ets:prev(Tab,Key) for a given type of registration object.
  531. %%
  532. %% See [http://www.erlang.org/doc/man/ets.html#prev-2].
  533. %% The registry behaves as an ordered_set table.
  534. %% @end
  535. %%
  536. prev(Context, K) ->
  537. {S, T} = get_s_t(Context),
  538. step(ets:prev(?TAB, K), S, T).
  539. step(Key, '_', '_') ->
  540. case Key of
  541. {{_,_,_},_} -> Key;
  542. _ -> '$end_of_table'
  543. end;
  544. step(Key, '_', T) ->
  545. case Key of
  546. {{T,_,_},_} -> Key;
  547. _ -> '$end_of_table'
  548. end;
  549. step(Key, S, '_') ->
  550. case Key of
  551. {{_, S, _}, _} -> Key;
  552. _ -> '$end_of_table'
  553. end;
  554. step(Key, S, T) ->
  555. case Key of
  556. {{T, S, _}, _} -> Key;
  557. _ -> '$end_of_table'
  558. end.
  559. %% @spec (Pid::pid()) -> ProcessInfo
  560. %% ProcessInfo = [{gproc, [{Key,Value}]} | ProcessInfo]
  561. %%
  562. %% @doc Similar to `process_info(Pid)' but with additional gproc info.
  563. %%
  564. %% Returns the same information as process_info(Pid), but with the
  565. %% addition of a `gproc' information item, containing the `{Key,Value}'
  566. %% pairs registered to the process.
  567. %% @end
  568. info(Pid) when is_pid(Pid) ->
  569. Items = [?MODULE | [ I || {I,_} <- process_info(self())]],
  570. [info(Pid,I) || I <- Items].
  571. %% @spec (Pid::pid(), Item::atom()) -> {Item, Info}
  572. %%
  573. %% @doc Similar to process_info(Pid, Item), but with additional gproc info.
  574. %%
  575. %% For `Item = gproc', this function returns a list of `{Key, Value}' pairs
  576. %% registered to the process Pid. For other values of Item, it returns the
  577. %% same as [http://www.erlang.org/doc/man/erlang.html#process_info-2].
  578. %% @end
  579. info(Pid, ?MODULE) ->
  580. Keys = ets:select(?TAB, [{ {{Pid,'$1'}}, [], ['$1'] }]),
  581. {?MODULE, lists:zf(
  582. fun(K) ->
  583. try V = get_value(K, Pid),
  584. {true, {K,V}}
  585. catch
  586. error:_ ->
  587. false
  588. end
  589. end, Keys)};
  590. info(Pid, I) ->
  591. process_info(Pid, I).
  592. %%% ==========================================================
  593. %% @hidden
  594. handle_cast({monitor_me, Pid}, S) ->
  595. erlang:monitor(process, Pid),
  596. {noreply, S}.
  597. %% @hidden
  598. handle_call({reg, {_T,l,_} = Key, Val}, {Pid,_}, S) ->
  599. case try_insert_reg(Key, Val, Pid) of
  600. true ->
  601. ensure_monitor(Pid),
  602. {reply, true, S};
  603. false ->
  604. {reply, badarg, S}
  605. end;
  606. handle_call({unreg, {_,l,_} = Key}, {Pid,_}, S) ->
  607. case ets:member(?TAB, {Pid,Key}) of
  608. true ->
  609. gproc_lib:remove_reg(Key, Pid),
  610. {reply, true, S};
  611. false ->
  612. {reply, badarg, S}
  613. end;
  614. handle_call({mreg, T, l, L}, {Pid,_}, S) ->
  615. try gproc_lib:insert_many(T, l, L, Pid) of
  616. {true,_} -> {reply, true, S};
  617. false -> {reply, badarg, S}
  618. catch
  619. error:_ -> {reply, badarg, S}
  620. end;
  621. handle_call({set, {_,l,_} = Key, Value}, {Pid,_}, S) ->
  622. case gproc_lib:do_set_value(Key, Value, Pid) of
  623. true ->
  624. {reply, true, S};
  625. false ->
  626. {reply, badarg, S}
  627. end;
  628. handle_call(_, _, S) ->
  629. {reply, badarg, S}.
  630. %% @hidden
  631. handle_info({'DOWN', _MRef, process, Pid, _}, S) ->
  632. process_is_down(Pid),
  633. {noreply, S};
  634. handle_info(_, S) ->
  635. {noreply, S}.
  636. %% @hidden
  637. code_change(_FromVsn, S, _Extra) ->
  638. {ok, S}.
  639. %% @hidden
  640. terminate(_Reason, _S) ->
  641. ok.
  642. call(Req) ->
  643. case gen_server:call(?MODULE, Req) of
  644. badarg -> erlang:error(badarg, Req);
  645. Reply -> Reply
  646. end.
  647. cast(Msg) ->
  648. gen_server:cast(?MODULE, Msg).
  649. try_insert_reg({T,l,_} = Key, Val, Pid) ->
  650. case gproc_lib:insert_reg(Key, Val, Pid, l) of
  651. false ->
  652. case ets:lookup(?TAB, {Key,T}) of
  653. [{_, OtherPid, _}] ->
  654. case is_process_alive(OtherPid) of
  655. true ->
  656. false;
  657. false ->
  658. process_is_down(Pid),
  659. true = gproc_lib:insert_reg(Key, Val, Pid, l)
  660. end;
  661. [] ->
  662. false
  663. end;
  664. true ->
  665. true
  666. end.
  667. process_is_down(Pid) ->
  668. Keys = ets:select(?TAB, [{{{Pid,'$1'}},
  669. [{'==',{element,2,'$1'},l}], ['$1']}]),
  670. ets:select_delete(?TAB, [{{{Pid,{'_',l,'_'}}}, [], [true]}]),
  671. ets:delete(?TAB, Pid),
  672. lists:foreach(fun(Key) -> gproc_lib:remove_reg_1(Key, Pid) end, Keys).
  673. create_tabs() ->
  674. ets:new(?MODULE, [ordered_set, public, named_table]).
  675. %% @hidden
  676. init([]) ->
  677. {ok, #state{}}.
  678. ensure_monitor(Pid) when node(Pid) == node() ->
  679. case ets:insert_new(?TAB, {Pid}) of
  680. false -> ok;
  681. true -> erlang:monitor(process, Pid)
  682. end;
  683. ensure_monitor(_) ->
  684. true.
  685. monitor_me() ->
  686. case ets:insert_new(?TAB, {self()}) of
  687. false -> true;
  688. true ->
  689. cast({monitor_me,self()}),
  690. true
  691. end.
  692. pattern([{'_', Gs, As}], T) ->
  693. ?l,
  694. {HeadPat, Vs} = headpat(T, '$1', '$2', '$3'),
  695. [{HeadPat, rewrite(Gs,Vs), rewrite(As,Vs)}];
  696. pattern([{{A,B,C},Gs,As}], Scope) ->
  697. ?l,
  698. {HeadPat, Vars} = headpat(Scope, A,B,C),
  699. [{HeadPat, rewrite(Gs,Vars), rewrite(As,Vars)}];
  700. pattern([{Head, Gs, As}], Scope) ->
  701. ?l,
  702. case is_var(Head) of
  703. {true,_N} ->
  704. HeadPat = {{{type(Scope),'_','_'},'_'},'_','_'},
  705. Vs = [{Head, obj_prod()}],
  706. %% {HeadPat, Vs} = headpat(Scope, A,B,C),
  707. %% the headpat function should somehow verify that Head is
  708. %% consistent with Scope (or should we add a guard?)
  709. [{HeadPat, rewrite(Gs, Vs), rewrite(As, Vs)}];
  710. false ->
  711. erlang:error(badarg)
  712. end.
  713. %% This is the expression to use in guards and the RHS to address the whole
  714. %% object, in its logical representation.
  715. obj_prod() ->
  716. {{ {element,1,{element,1,'$_'}},
  717. {element,2,'$_'},
  718. {element,3,'$_'} }}.
  719. obj_prod_l() ->
  720. [ {element,1,{element,1,'$_'}},
  721. {element,2,'$_'},
  722. {element,3,'$_'} ].
  723. headpat({S, T}, V1,V2,V3) when S==global; S==local; S==all ->
  724. headpat(type(T), scope(S), V1,V2,V3);
  725. headpat(T, V1, V2, V3) when is_atom(T) ->
  726. headpat(type(T), l, V1, V2, V3);
  727. headpat(_, _, _, _) -> erlang:error(badarg).
  728. headpat(T, C, V1,V2,V3) ->
  729. Rf = fun(Pos) ->
  730. {element,Pos,{element,1,{element,1,'$_'}}}
  731. end,
  732. K2 = if T==n orelse T==a -> T;
  733. true -> '_'
  734. end,
  735. {Kp,Vars} = case V1 of
  736. {Vt,Vc,Vn} ->
  737. ?l,
  738. {T1,Vs1} = subst(T,Vt,fun() -> Rf(1) end,[]),
  739. {C1,Vs2} = subst(C,Vc,fun() -> Rf(2) end,Vs1),
  740. {{T1,C1,Vn}, Vs2};
  741. '_' ->
  742. ?l,
  743. {{T,C,'_'}, []};
  744. _ ->
  745. ?l,
  746. case is_var(V1) of
  747. {true,_} ->
  748. {{T,C,V1}, [{V1, {element,1,
  749. {element,1,'$_'}}}]};
  750. false ->
  751. erlang:error(badarg)
  752. end
  753. end,
  754. {{{Kp,K2},V2,V3}, Vars}.
  755. %% l(L) -> L.
  756. subst(X, '_', _F, Vs) ->
  757. {X, Vs};
  758. subst(X, V, F, Vs) ->
  759. case is_var(V) of
  760. {true,_} ->
  761. {X, [{V,F()}|Vs]};
  762. false ->
  763. {V, Vs}
  764. end.
  765. scope(all) -> '_';
  766. scope(global) -> g;
  767. scope(local) -> l.
  768. type(all) -> '_';
  769. type(T) when T==n; T==p; T==c; T==a -> T;
  770. type(names) -> n;
  771. type(props) -> p;
  772. type(counters) -> c;
  773. type(aggr_counters) -> a.
  774. keypat(Context) ->
  775. {S,T} = get_s_t(Context),
  776. {{T,S,'_'},'_'}.
  777. get_s_t({S,T}) -> {scope(S), type(T)};
  778. get_s_t(T) when is_atom(T) ->
  779. {l, type(T)}.
  780. is_var('$1') -> {true,1};
  781. is_var('$2') -> {true,2};
  782. is_var('$3') -> {true,3};
  783. is_var('$4') -> {true,4};
  784. is_var('$5') -> {true,5};
  785. is_var('$6') -> {true,6};
  786. is_var('$7') -> {true,7};
  787. is_var('$8') -> {true,8};
  788. is_var('$9') -> {true,9};
  789. is_var(X) when is_atom(X) ->
  790. case atom_to_list(X) of
  791. "$" ++ Tl ->
  792. try N = list_to_integer(Tl),
  793. {true,N}
  794. catch
  795. error:_ ->
  796. false
  797. end;
  798. _ ->
  799. false
  800. end;
  801. is_var(_) -> false.
  802. rewrite(Gs, R) ->
  803. [rewrite1(G, R) || G <- Gs].
  804. rewrite1('$_', _) ->
  805. obj_prod();
  806. rewrite1('$$', _) ->
  807. obj_prod_l();
  808. rewrite1(Guard, R) when is_tuple(Guard) ->
  809. list_to_tuple([rewrite1(G, R) || G <- tuple_to_list(Guard)]);
  810. rewrite1(Exprs, R) when is_list(Exprs) ->
  811. [rewrite1(E, R) || E <- Exprs];
  812. rewrite1(V, R) when is_atom(V) ->
  813. case is_var(V) of
  814. {true,_N} ->
  815. case lists:keysearch(V, 1, R) of
  816. {value, {_, V1}} ->
  817. V1;
  818. false ->
  819. V
  820. end;
  821. false ->
  822. V
  823. end;
  824. rewrite1(Expr, _) ->
  825. Expr.
  826. %% @spec (Context::context()) -> any()
  827. %%
  828. %% @doc
  829. %% @equiv table(Context, [])
  830. %% @end
  831. %%
  832. table(Context) ->
  833. table(Context, []).
  834. %% @spec (Context::context(), Opts) -> any()
  835. %%
  836. %% @doc QLC table generator for the gproc registry.
  837. %% Context specifies which subset of the registry should be queried.
  838. %% See [http://www.erlang.org/doc/man/qlc.html].
  839. %% @end
  840. table(Ctxt, Opts) ->
  841. [Traverse, NObjs] = [proplists:get_value(K,Opts,Def) ||
  842. {K,Def} <- [{traverse,select}, {n_objects,100}]],
  843. TF = case Traverse of
  844. first_next ->
  845. fun() -> qlc_next(Ctxt, first(Ctxt)) end;
  846. last_prev -> fun() -> qlc_prev(Ctxt, last(Ctxt)) end;
  847. select ->
  848. fun(MS) -> qlc_select(select(Ctxt, MS, NObjs)) end;
  849. {select,MS} ->
  850. fun() -> qlc_select(select(Ctxt, MS, NObjs)) end;
  851. _ ->
  852. erlang:error(badarg, [Ctxt,Opts])
  853. end,
  854. InfoFun = fun(indices) -> [2];
  855. (is_unique_objects) -> is_unique(Ctxt);
  856. (keypos) -> 1;
  857. (is_sorted_key) -> true;
  858. (num_of_objects) ->
  859. %% this is just a guesstimate.
  860. trunc(ets:info(?TAB,size) / 2.5)
  861. end,
  862. LookupFun =
  863. case Traverse of
  864. {select, _MS} -> undefined;
  865. _ -> fun(Pos, Ks) -> qlc_lookup(Ctxt, Pos, Ks) end
  866. end,
  867. qlc:table(TF, [{info_fun, InfoFun},
  868. {lookup_fun, LookupFun}] ++ [{K,V} || {K,V} <- Opts,
  869. K =/= traverse,
  870. K =/= n_objects]).
  871. qlc_lookup(_Scope, 1, Keys) ->
  872. lists:flatmap(
  873. fun(Key) ->
  874. ets:select(?TAB, [{ {{Key,'_'},'_','_'}, [],
  875. [{{ {element,1,{element,1,'$_'}},
  876. {element,2,'$_'},
  877. {element,3,'$_'} }}] }])
  878. end, Keys);
  879. qlc_lookup(Scope, 2, Pids) ->
  880. lists:flatmap(fun(Pid) ->
  881. Found =
  882. ets:select(?TAB, [{ {{Pid,keypat(Scope)}},
  883. [], ['$_']}]),
  884. lists:flatmap(
  885. fun({{_,{T,_,_}=K}}) ->
  886. K2 = if T==n orelse T==a -> T;
  887. true -> Pid
  888. end,
  889. case ets:lookup(?TAB, {K,K2}) of
  890. [{{Key,_},_,Value}] ->
  891. [{Key, Pid, Value}];
  892. [] ->
  893. []
  894. end
  895. end, Found)
  896. end, Pids).
  897. qlc_next(_, '$end_of_table') -> [];
  898. qlc_next(Scope, K) ->
  899. case ets:lookup(?TAB, K) of
  900. [{{Key,_}, Pid, V}] ->
  901. [{Key,Pid,V} | fun() -> qlc_next(Scope, next(Scope, K)) end];
  902. [] ->
  903. qlc_next(Scope, next(Scope, K))
  904. end.
  905. qlc_prev(_, '$end_of_table') -> [];
  906. qlc_prev(Scope, K) ->
  907. case ets:lookup(?TAB, K) of
  908. [{{Key,_},Pid,V}] ->
  909. [{Key,Pid,V} | fun() -> qlc_prev(Scope, prev(Scope, K)) end];
  910. [] ->
  911. qlc_prev(Scope, prev(Scope, K))
  912. end.
  913. qlc_select('$end_of_table') ->
  914. [];
  915. qlc_select({Objects, Cont}) ->
  916. Objects ++ fun() -> qlc_select(ets:select(Cont)) end.
  917. is_unique(names) -> true;
  918. is_unique(aggr_counters) -> true;
  919. is_unique({_, names}) -> true;
  920. is_unique({_, aggr_counters}) -> true;
  921. is_unique(n) -> true;
  922. is_unique(a) -> true;
  923. is_unique({_,n}) -> true;
  924. is_unique({_,a}) -> true;
  925. is_unique(_) -> false.