ejabberd源码分析及开发系列(2) router模块分析

  router模块是xmpp 消息包在每个节点上的主router。它根据每个消息包的目的域对消息包进行路由。该模块有一张route表。首先根据消息包的目的地部分去搜索route表, 如果找到的话,就更加local_hint来判断是否进行相关的处理还是将该消息包路由到相应的进程,如果没有找到,就发送到S2S manager。

  下面来对ejabberd_router.erl源代码进行分析。

  ejabberd_router.erl实现了gen_server的behaviour用户实现异步的route功能。通过直接调用do_route可以实现同步的消息路由功能。

  首先是介绍用来存储路由信息的数据表,该表的结构如下

  

1 -record(route, {domain, pid, local_hint}).
View Code

  首先domain表示目的地的域,pid表示消息包的目的路由进程,local_hint就包含了对该消息包进行处理的相关信息。

  接着查看数据表的创建属性

1     mnesia:create_table(route,
2             [{ram_copies, [node()]},
3              {type, bag},
4              {attributes, record_info(fields, route)}]),
5    

  可以知道该数据表示一个bag类型,由此可得同一个domain可以对应多条route,这样是为了对可以根据不同的策略对消息路由进行均衡。均衡相关内容下面在详细分析

 

  在本模块中功能主要涉及两个函数一个是register_route, 另一个是do_route。

  首先对register_route进行分析。

 

 1 register_route(Domain, LocalHint) ->
 2     case jlib:nameprep(Domain) of 
 3       error -> erlang:error({invalid_domain, Domain}); 
 4       LDomain -> 
 5       Pid = self(), 
 6       case get_component_number(LDomain) of
 7         undefined ->
 8         F = fun () ->
 9                 mnesia:write(#route{domain = LDomain, pid = Pid,
10                         local_hint = LocalHint})
11             end,
12         mnesia:transaction(F);
13         N ->
14         F = fun () ->
15                 case mnesia:wread({route, LDomain}) of
16                   [] ->
17                   mnesia:write(#route{domain = LDomain,
18                               pid = Pid,
19                               local_hint = 1}),
20                   lists:foreach(fun (I) ->
21                             mnesia:write(#route{domain
22                                         =
23                                         LDomain,
24                                         pid
25                                         =
26                                         undefined,
27                                         local_hint
28                                         =
29                                         I})
30                         end,
31                         lists:seq(2, N));
32                   Rs ->
33                   lists:any(fun (#route{pid = undefined,
34                             local_hint = I} =
35                              R) ->
36                             mnesia:write(#route{domain =
37                                         LDomain,
38                                     pid =
39                                         Pid,
40                                     local_hint
41                                         =
42                                         I}),
43                             mnesia:delete_object(R),
44                             true;
45                         (_) -> false
46                         end,
47                         Rs)
48                 end
49             end,
50         mnesia:transaction(F)
51       end
52     end.

 

   首先第二行判断Domain的格式是否正确,错误通知错误, 正确的话就首先获得该请求进程的pid,然后根据Domain查找相应的组件的数据,如果是未定义的,则直接将一条route记录写进数据库用于以后的消息路由,如果是有定义的,则匹配到相应的组件数即N。然后根据Domain从数据库读出相应的route记录。如果记录为空, 则将构造一条route记录写进数据库,然后构造N-1条默认的route写进数据库。如果记录不为空,则则将其中一条默认的记录修改为本请求构造的有效记录。

  

  然后是对

你可能感兴趣的:(ejabberd源码分析及开发系列(2) router模块分析)