PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/test/gproc_dist_tests.erl

http://github.com/esl/gproc
Erlang | 500 lines | 422 code | 41 blank | 37 comment | 16 complexity | 95b7cf7e253cce62170c828cecfe739c MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. %% -*- erlang-indent-level: 4; indent-tabs-mode: nil -*-
  2. %% ``The contents of this file are subject to the Erlang Public License,
  3. %% Version 1.1, (the "License"); you may not use this file except in
  4. %% compliance with the License. You should have received a copy of the
  5. %% Erlang Public License along with this software. If not, it can be
  6. %% retrieved via the world wide web at http://www.erlang.org/.
  7. %%
  8. %% Software distributed under the License is distributed on an "AS IS"
  9. %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  10. %% the License for the specific language governing rights and limitations
  11. %% under the License.
  12. %%
  13. %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
  14. %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
  15. %% AB. All Rights Reserved.''
  16. %%
  17. %% @author Ulf Wiger <ulf.wiger@erlang-solutions.com>
  18. %%
  19. -module(gproc_dist_tests).
  20. -ifdef(TEST).
  21. -include_lib("eunit/include/eunit.hrl").
  22. -export([t_spawn/1, t_spawn_reg/2]).
  23. dist_test_() ->
  24. {timeout, 120,
  25. [{setup,
  26. fun() ->
  27. case run_dist_tests() of
  28. true ->
  29. Ns = start_slaves([dist_test_n1, dist_test_n2]),
  30. ?assertMatch({[ok,ok],[]},
  31. rpc:multicall(Ns, application, set_env,
  32. [gproc, gproc_dist, Ns])),
  33. ?assertMatch({[ok,ok],[]},
  34. rpc:multicall(
  35. Ns, application, start, [gproc])),
  36. Ns;
  37. false ->
  38. skip
  39. end
  40. end,
  41. fun(_Ns) ->
  42. ok
  43. end,
  44. fun(skip) -> [];
  45. (Ns) when is_list(Ns) ->
  46. {inorder,
  47. [
  48. {inorder, [
  49. fun() ->
  50. ?debugVal(t_simple_reg(Ns))
  51. end,
  52. fun() ->
  53. ?debugVal(t_simple_reg_or_locate(Ns))
  54. end,
  55. fun() ->
  56. ?debugVal(t_simple_counter(Ns))
  57. end,
  58. fun() ->
  59. ?debugVal(t_aggr_counter(Ns))
  60. end,
  61. fun() ->
  62. ?debugVal(t_update_counters(Ns))
  63. end,
  64. fun() ->
  65. ?debugVal(t_shared_counter(Ns))
  66. end,
  67. fun() ->
  68. ?debugVal(t_mreg(Ns))
  69. end,
  70. fun() ->
  71. ?debugVal(t_await_reg(Ns))
  72. end,
  73. fun() ->
  74. ?debugVal(t_await_self(Ns))
  75. end,
  76. fun() ->
  77. ?debugVal(t_await_reg_exists(Ns))
  78. end,
  79. fun() ->
  80. ?debugVal(t_give_away(Ns))
  81. end,
  82. fun() ->
  83. ?debugVal(t_sync(Ns))
  84. end,
  85. fun() ->
  86. ?debugVal(t_monitor(Ns))
  87. end,
  88. fun() ->
  89. ?debugVal(t_standby_monitor(Ns))
  90. end,
  91. fun() ->
  92. ?debugVal(t_follow_monitor(Ns))
  93. end,
  94. fun() ->
  95. ?debugVal(t_subscribe(Ns))
  96. end
  97. ]
  98. },
  99. fun() ->
  100. ?debugVal(t_sync_cand_dies(Ns))
  101. end,
  102. {timeout, 90, [fun() ->
  103. ?debugVal(t_fail_node(Ns))
  104. end]}
  105. ]}
  106. end
  107. }]}.
  108. run_dist_tests() ->
  109. case os:getenv("GPROC_DIST") of
  110. "true" -> true;
  111. "false" -> false;
  112. false ->
  113. case code:ensure_loaded(gen_leader) of
  114. {error, nofile} ->
  115. false;
  116. _ ->
  117. true
  118. end
  119. end.
  120. -define(T_NAME, {n, g, {?MODULE, ?LINE, erlang:now()}}).
  121. -define(T_KVL, [{foo, "foo"}, {bar, "bar"}]).
  122. -define(T_COUNTER, {c, g, {?MODULE, ?LINE}}).
  123. t_simple_reg([H|_] = Ns) ->
  124. Name = ?T_NAME,
  125. P = t_spawn_reg(H, Name),
  126. ?assertMatch(ok, t_lookup_everywhere(Name, Ns, P)),
  127. ?assertMatch(true, t_call(P, {apply, gproc, unreg, [Name]})),
  128. ?assertMatch(ok, t_lookup_everywhere(Name, Ns, undefined)),
  129. ?assertMatch(ok, t_call(P, die)).
  130. t_simple_reg_or_locate([A,B|_] = _Ns) ->
  131. Name = ?T_NAME,
  132. P1 = t_spawn(A),
  133. Ref = erlang:monitor(process, P1),
  134. ?assertMatch({P1, the_value},
  135. t_call(P1, {apply, gproc, reg_or_locate, [Name, the_value]})),
  136. P2 = t_spawn(B),
  137. Ref2 = erlang:monitor(process, P2),
  138. ?assertMatch({P1, the_value},
  139. t_call(P2, {apply, gproc, reg_or_locate, [Name, other_value]})),
  140. ?assertMatch(ok, t_call(P1, die)),
  141. ?assertMatch(ok, t_call(P2, die)),
  142. flush_down(Ref),
  143. flush_down(Ref2).
  144. flush_down(Ref) ->
  145. receive
  146. {'DOWN', Ref, _, _, _} ->
  147. ok
  148. after 1000 ->
  149. erlang:error({timeout, [flush_down, Ref]})
  150. end.
  151. t_simple_counter([H|_] = Ns) ->
  152. Ctr = ?T_COUNTER,
  153. P = t_spawn_reg(H, Ctr, 3),
  154. ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 3)),
  155. ?assertMatch(5, t_call(P, {apply, gproc, update_counter, [Ctr, 2]})),
  156. ?assertMatch(ok, t_read_everywhere(Ctr, P, Ns, 5)),
  157. ?assertMatch(ok, t_call(P, die)).
  158. t_shared_counter([H|_] = Ns) ->
  159. Ctr = ?T_COUNTER,
  160. P = t_spawn_reg_shared(H, Ctr, 3),
  161. ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 3)),
  162. ?assertMatch(5, t_call(P, {apply, gproc, update_shared_counter, [Ctr, 2]})),
  163. ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 5)),
  164. ?assertMatch(ok, t_call(P, die)),
  165. ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 5)),
  166. ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, 5)), % twice
  167. P1 = t_spawn(H),
  168. ?assertMatch(true, t_call(P1, {apply, gproc, unreg_shared, [Ctr]})),
  169. ?assertMatch(ok, t_read_everywhere(Ctr, shared, Ns, badarg)).
  170. t_aggr_counter([H1,H2|_] = Ns) ->
  171. {c,g,Nm} = Ctr = ?T_COUNTER,
  172. Aggr = {a,g,Nm},
  173. Pc1 = t_spawn_reg(H1, Ctr, 3),
  174. Pa = t_spawn_reg(H2, Aggr),
  175. ?assertMatch(ok, t_read_everywhere(Ctr, Pc1, Ns, 3)),
  176. ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 3)),
  177. Pc2 = t_spawn_reg(H2, Ctr, 3),
  178. ?assertMatch(ok, t_read_everywhere(Ctr, Pc2, Ns, 3)),
  179. ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 6)),
  180. ?assertMatch(5, t_call(Pc1, {apply, gproc, update_counter, [Ctr, 2]})),
  181. ?assertMatch(ok, t_read_everywhere(Ctr, Pc1, Ns, 5)),
  182. ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 8)),
  183. ?assertMatch(ok, t_call(Pc1, die)),
  184. ?assertMatch(ok, t_read_everywhere(Aggr, Pa, Ns, 3)),
  185. ?assertMatch(ok, t_call(Pc2, die)),
  186. ?assertMatch(ok, t_call(Pa, die)).
  187. t_update_counters([H1,H2|_] = Ns) ->
  188. {c,g,N1} = C1 = ?T_COUNTER,
  189. A1 = {a,g,N1},
  190. C2 = ?T_COUNTER,
  191. P1 = t_spawn_reg(H1, C1, 2),
  192. P12 = t_spawn_reg(H2, C1, 2),
  193. P2 = t_spawn_reg(H2, C2, 1),
  194. Pa1 = t_spawn_reg(H2, A1),
  195. ?assertMatch(ok, t_read_everywhere(C1, P1, Ns, 2)),
  196. ?assertMatch(ok, t_read_everywhere(C1, P12, Ns, 2)),
  197. ?assertMatch(ok, t_read_everywhere(C2, P2, Ns, 1)),
  198. ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 4)),
  199. ?debugFmt("code:which(gproc_dist) = ~p~n", [code:which(gproc_dist)]),
  200. ?assertMatch([{C1,P1, 3},
  201. {C1,P12,4},
  202. {C2,P2, 0}], t_call(P1, {apply, gproc, update_counters,
  203. [g, [{C1,P1,1},{C1,P12,2},{C2,P2,{-2,0,0}}]]})),
  204. ?assertMatch(ok, t_read_everywhere(C1, P1, Ns, 3)),
  205. ?assertMatch(ok, t_read_everywhere(C1, P12, Ns, 4)),
  206. ?assertMatch(ok, t_read_everywhere(C2, P2, Ns, 0)),
  207. ?assertMatch(ok, t_read_everywhere(A1, Pa1, Ns, 7)),
  208. ?assertMatch(ok, t_call(P1, die)),
  209. ?assertMatch(ok, t_call(P12, die)),
  210. ?assertMatch(ok, t_call(P2, die)).
  211. t_mreg([H|_] = Ns) ->
  212. Kvl = ?T_KVL,
  213. Keys = [K || {K,_} <- Kvl],
  214. P = t_spawn_mreg(H, Kvl),
  215. [?assertMatch(ok, t_lookup_everywhere({n,g,K}, Ns, P)) || K <- Keys],
  216. ?assertMatch(true, t_call(P, {apply, gproc, munreg, [n, g, Keys]})),
  217. [?assertMatch(ok, t_lookup_everywhere({n,g,K},Ns,undefined)) || K <- Keys],
  218. ?assertMatch(ok, t_call(P, die)).
  219. t_await_reg([A,B|_]) ->
  220. Name = ?T_NAME,
  221. P = t_spawn(A),
  222. Ref = erlang:monitor(process, P),
  223. P ! {self(), Ref, {apply, gproc, await, [Name]}},
  224. t_sleep(),
  225. P1 = t_spawn_reg(B, Name),
  226. ?assert(P1 == receive
  227. {P, Ref, Res} ->
  228. element(1, Res);
  229. {'DOWN', Ref, _, _, Reason} ->
  230. erlang:error(Reason);
  231. Other ->
  232. erlang:error({received,Other})
  233. end),
  234. ?assertMatch(ok, t_call(P, die)),
  235. flush_down(Ref),
  236. ?assertMatch(ok, t_call(P1, die)).
  237. t_await_self([A|_]) ->
  238. Name = ?T_NAME,
  239. P = t_spawn(A, false), % don't buffer unknowns
  240. Ref = t_call(P, {apply, gproc, nb_wait, [Name]}),
  241. ?assertMatch(ok, t_call(P, {selective, true})),
  242. ?assertMatch(true, t_call(P, {apply, gproc, reg, [Name, some_value]})),
  243. ?assertMatch({registered, {Name, P, some_value}},
  244. t_call(P, {apply_fun, fun() ->
  245. receive
  246. {gproc, Ref, R, Wh} ->
  247. {R, Wh}
  248. after 10000 ->
  249. timeout
  250. end
  251. end})),
  252. ?assertMatch(ok, t_call(P, {selective, false})),
  253. ?assertMatch(true, t_call(P, {apply, gproc, unreg, [Name]})).
  254. t_await_reg_exists([A,B|_]) ->
  255. Name = ?T_NAME,
  256. P = t_spawn(A),
  257. Ref = erlang:monitor(process, P),
  258. P1 = t_spawn_reg(B, Name),
  259. P ! {self(), Ref, {apply, gproc, await, [Name]}},
  260. ?assert(P1 == receive
  261. {P, Ref, Res} ->
  262. element(1, Res);
  263. {'DOWN', Ref, _, _, Reason} ->
  264. erlang:error(Reason);
  265. Other ->
  266. erlang:error({received,Other})
  267. end),
  268. ?assertMatch(ok, t_call(P, die)),
  269. ?assertMatch(ok, t_call(P1, die)).
  270. t_give_away([A,B|_] = Ns) ->
  271. Na = ?T_NAME,
  272. Nb = ?T_NAME,
  273. Pa = t_spawn_reg(A, Na),
  274. Pb = t_spawn_reg(B, Nb),
  275. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
  276. ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
  277. ?assertMatch(Pb, t_call(Pa, {apply, gproc, give_away, [Na, Nb]})),
  278. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pb)),
  279. ?assertMatch(Pa, t_call(Pb, {apply, gproc, give_away, [Na, Pa]})),
  280. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pa)),
  281. ?assertMatch(ok, t_call(Pa, die)),
  282. ?assertMatch(ok, t_call(Pb, die)).
  283. t_sync(Ns) ->
  284. %% Don't really know how to test this...
  285. [?assertMatch(true, rpc:call(N, gproc_dist, sync, []))
  286. || N <- Ns].
  287. t_monitor([A,B|_]) ->
  288. Na = ?T_NAME,
  289. Pa = t_spawn_reg(A, Na),
  290. Pb = t_spawn(B, _Selective = true),
  291. Ref = t_call(Pb, {apply, gproc, monitor, [Na]}),
  292. ?assert(is_reference(Ref)),
  293. ?assertMatch(ok, t_call(Pa, die)),
  294. ?assertMatch({gproc,unreg,Ref,Na}, got_msg(Pb, gproc)),
  295. Pc = t_spawn_reg(A, Na),
  296. Ref1 = t_call(Pb, {apply, gproc, monitor, [Na]}),
  297. ?assertMatch(true, t_call(Pc, {apply, gproc, unreg, [Na]})),
  298. ?assertMatch({gproc,unreg,Ref1,Na}, got_msg(Pb, gproc)).
  299. t_standby_monitor([A,B|_] = Ns) ->
  300. Na = ?T_NAME,
  301. Pa = t_spawn_reg(A, Na),
  302. Pb = t_spawn(B, _Selective = true),
  303. Ref = t_call(Pb, {apply, gproc, monitor, [Na, standby]}),
  304. ?assert(is_reference(Ref)),
  305. ?assertMatch(ok, t_call(Pa, die)),
  306. ?assertMatch({gproc,{failover,Pb},Ref,Na}, got_msg(Pb, gproc)),
  307. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pb)),
  308. Pc = t_spawn(A, true),
  309. Ref1 = t_call(Pc, {apply, gproc, monitor, [Na, standby]}),
  310. ?assertMatch(true, t_call(Pb, {apply, gproc, unreg, [Na]})),
  311. ?assertMatch({gproc,unreg,Ref1,Na}, got_msg(Pc, gproc)),
  312. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, undefined)).
  313. t_follow_monitor([A,B|_] = Ns) ->
  314. Na = ?T_NAME,
  315. Pa = t_spawn(A, _Selective = true),
  316. Ref = t_call(Pa, {apply, gproc, monitor, [Na, follow]}),
  317. {gproc,unreg,Ref,Na} = got_msg(Pa),
  318. Pb = t_spawn_reg(A, Na),
  319. {gproc,registered,Ref,Na} = got_msg(Pa),
  320. ok = t_call(Pb, die),
  321. ok = t_call(Pa, die).
  322. t_subscribe([A,B|_] = Ns) ->
  323. Na = ?T_NAME,
  324. Pb = t_spawn(B, _Selective = true),
  325. ?assertEqual(ok, t_call(Pb, {apply, gproc_monitor, subscribe, [Na]})),
  326. ?assertMatch({gproc_monitor, Na, undefined}, got_msg(Pb, gproc_monitor)),
  327. Pa = t_spawn_reg(A, Na),
  328. ?assertMatch({gproc_monitor, Na, Pa}, got_msg(Pb, gproc_monitor)),
  329. Pc = t_spawn(A),
  330. t_call(Pa, {apply, gproc, give_away, [Na, Pc]}),
  331. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, Pc)),
  332. ?assertEqual({gproc_monitor,Na,{migrated,Pc}}, got_msg(Pb, gproc_monitor)),
  333. ?assertEqual(ok, t_call(Pc, die)),
  334. ?assertEqual({gproc_monitor,Na,undefined}, got_msg(Pb, gproc_monitor)),
  335. ok.
  336. %% got_msg(Pb, Tag) ->
  337. %% t_call(Pb,
  338. %% {apply_fun,
  339. %% fun() ->
  340. %% receive
  341. %% M when element(1, M) == Tag ->
  342. %% M
  343. %% after 1000 ->
  344. %% erlang:error({timeout, got_msg, [Pb, Tag]})
  345. %% end
  346. %% end}).
  347. %% Verify that the gproc_dist:sync() call returns true even if a candidate dies
  348. %% while the sync is underway. This test makes use of sys:suspend() to ensure that
  349. %% the other candidate doesn't respond too quickly.
  350. t_sync_cand_dies([A,B|_]) ->
  351. Leader = rpc:call(A, gproc_dist, get_leader, []),
  352. Other = case Leader of
  353. A -> B;
  354. B -> A
  355. end,
  356. ?assertMatch(ok, rpc:call(Other, sys, suspend, [gproc_dist])),
  357. P = rpc:call(Other, erlang, whereis, [gproc_dist]),
  358. Key = rpc:async_call(Leader, gproc_dist, sync, []),
  359. %% The overall timeout for gproc_dist:sync() is 5 seconds. Here, we should
  360. %% still be waiting.
  361. ?assertMatch(timeout, rpc:nb_yield(Key, 1000)),
  362. exit(P, kill),
  363. %% The leader should detect that the other candidate died and respond
  364. %% immediately. Therefore, we should have our answer well within 1 sec.
  365. ?assertMatch({value, true}, rpc:nb_yield(Key, 1000)).
  366. t_fail_node([A,B|_] = Ns) ->
  367. Na = ?T_NAME,
  368. Nb = ?T_NAME,
  369. Pa = t_spawn_reg(A, Na),
  370. Pb = t_spawn_reg(B, Nb),
  371. ?assertMatch(ok, rpc:call(A, application, stop, [gproc])),
  372. ?assertMatch(ok, t_lookup_everywhere(Na, Ns -- [A], undefined)),
  373. ?assertMatch(ok, t_lookup_everywhere(Nb, Ns -- [A], Pb)),
  374. ?assertMatch(ok, rpc:call(A, application, start, [gproc])),
  375. ?assertMatch(ok, t_lookup_everywhere(Na, Ns, undefined)),
  376. ?assertMatch(ok, t_lookup_everywhere(Nb, Ns, Pb)),
  377. ?assertMatch(ok, t_call(Pa, die)),
  378. ?assertMatch(ok, t_call(Pb, die)).
  379. t_sleep() ->
  380. timer:sleep(500).
  381. t_lookup_everywhere(Key, Nodes, Exp) ->
  382. t_lookup_everywhere(Key, Nodes, Exp, 3).
  383. t_lookup_everywhere(Key, _, Exp, 0) ->
  384. {lookup_failed, Key, Exp};
  385. t_lookup_everywhere(Key, Nodes, Exp, I) ->
  386. Expected = [{N, Exp} || N <- Nodes],
  387. Found = [{N,rpc:call(N, gproc, where, [Key])} || N <- Nodes],
  388. if Expected =/= Found ->
  389. ?debugFmt("lookup ~p failed~n"
  390. "(Expected: ~p;~n"
  391. " Found : ~p), retrying...~n",
  392. [Key, Expected, Found]),
  393. t_sleep(),
  394. t_lookup_everywhere(Key, Nodes, Exp, I-1);
  395. true ->
  396. ok
  397. end.
  398. t_read_everywhere(Key, Pid, Nodes, Exp) ->
  399. t_read_everywhere(Key, Pid, Nodes, Exp, 3).
  400. t_read_everywhere(Key, _, _, Exp, 0) ->
  401. {read_failed, Key, Exp};
  402. t_read_everywhere(Key, Pid, Nodes, Exp, I) ->
  403. Expected = [{N, Exp} || N <- Nodes],
  404. Found = [{N, read_result(rpc:call(N, gproc, get_value, [Key, Pid]))}
  405. || N <- Nodes],
  406. if Expected =/= Found ->
  407. ?debugFmt("read ~p failed~n"
  408. "(Expected: ~p;~n"
  409. " Found : ~p), retrying...~n",
  410. [{Key, Pid}, Expected, Found]),
  411. t_sleep(),
  412. t_read_everywhere(Key, Pid, Nodes, Exp, I-1);
  413. true ->
  414. ok
  415. end.
  416. read_result({badrpc, {'EXIT', {badarg, _}}}) -> badarg;
  417. read_result(R) -> R.
  418. t_spawn(Node) -> gproc_test_lib:t_spawn(Node).
  419. t_spawn(Node, Selective) -> gproc_test_lib:t_spawn(Node, Selective).
  420. t_spawn_mreg(Node, KVL) -> gproc_test_lib:t_spawn_mreg(Node, KVL).
  421. t_spawn_reg(Node, N) -> gproc_test_lib:t_spawn_reg(Node, N).
  422. t_spawn_reg(Node, N, V) -> gproc_test_lib:t_spawn_reg(Node, N, V).
  423. t_spawn_reg_shared(Node, N, V) -> gproc_test_lib:t_spawn_reg_shared(Node, N, V).
  424. got_msg(P) -> gproc_test_lib:got_msg(P).
  425. got_msg(P, Tag) -> gproc_test_lib:got_msg(P, Tag).
  426. t_call(P, Req) ->
  427. gproc_test_lib:t_call(P, Req).
  428. start_slaves(Ns) ->
  429. [H|T] = Nodes = [start_slave(N) || N <- Ns],
  430. _ = [rpc:call(H, net_adm, ping, [N]) || N <- T],
  431. Nodes.
  432. start_slave(Name) ->
  433. case node() of
  434. nonode@nohost ->
  435. os:cmd("epmd -daemon"),
  436. {ok, _} = net_kernel:start([gproc_master, shortnames]);
  437. _ ->
  438. ok
  439. end,
  440. {Pa, Pz} = paths(),
  441. Paths = "-pa ./ -pz ../ebin" ++
  442. lists:flatten([[" -pa " ++ Path || Path <- Pa],
  443. [" -pz " ++ Path || Path <- Pz]]),
  444. {ok, Node} = slave:start(host(), Name, Paths),
  445. Node.
  446. paths() ->
  447. Path = code:get_path(),
  448. {ok, [[Root]]} = init:get_argument(root),
  449. {Pas, Rest} = lists:splitwith(fun(P) ->
  450. not lists:prefix(Root, P)
  451. end, Path),
  452. {_, Pzs} = lists:splitwith(fun(P) ->
  453. lists:prefix(Root, P)
  454. end, Rest),
  455. {Pas, Pzs}.
  456. host() ->
  457. [_Name, Host] = re:split(atom_to_list(node()), "@", [{return, list}]),
  458. list_to_atom(Host).
  459. -endif.