Erlang/Elixir 深入浅出 Mnesia-schema 创建 (2)

DavidAlphaFox · 发布于 2017年12月19日 · 389 次阅读
84794b

FALLBACK.BUP生成schema.DAT时机

前面的文章提到了如何生成FALLBACK.BUP,但没有提到FALLBACK.BUP是怎样生成schema.DAT文件的。想要知道FALLBACK.BUP是如何生成schema.DAT,就需要去观察Mnesia的启动流程和监控树。

通过对代码的分析,可以非常清晰的看到,Mnesia的主要进程都被mnesia_kernel_sup这个监控者进程下

init([]) ->
    ProcLib = [mnesia_monitor, proc_lib],
    Flags = {one_for_all, 0, timer:hours(24)}, % Trust the top supervisor
    %% 最先启动的是mnesia_monitor
    %% mnesia_monitor持有mnesia_gvar和mnesia_stats两张ets表
    %% mnesia的全局变量全都保存在此处
    Workers = [worker_spec(mnesia_monitor, timer:seconds(3), [gen_server]),
        %% mnesia_subscr 创建订阅管理进程
        %% 自动将mnesia_event加入到系统订阅表中
           worker_spec(mnesia_subscr, timer:seconds(3), [gen_server]),
        %% mnesia的锁管理进程
           worker_spec(mnesia_locker, timer:seconds(3), ProcLib),
         %% mnesia恢复进程
           worker_spec(mnesia_recover, timer:minutes(3), [gen_server]),
         %% mnesia事务进程
           worker_spec(mnesia_tm, timer:seconds(30), ProcLib),
         %% 检察点监控者进程
           supervisor_spec(mnesia_checkpoint_sup),
         %% snmp监控者进程
           supervisor_spec(mnesia_snmp_sup),
         %% mnesia主控进程
           worker_spec(mnesia_controller, timer:seconds(3), [gen_server]),
         %% mnesia数据加载进程
           worker_spec(mnesia_late_loader, timer:seconds(3), ProcLib)
          ],
    {ok, {Flags, Workers}}.

通过逐个进程的检察,在mnesia_tm进程初始化的时候,会通过mnesia_bup:tm_fallback_start函数来使用FALLBACK.BUP进行数据恢复,在此过程中就会生成schema.DAT。

恢复流程

tm_fallback_start函数

在mnesia_bup:tm_fallback_start函数中,整个操作过程都是锁住schema表进行操作的,在这个过程中,本节点上所有的其它schema操作都会进行等待。同时,这个函数的整体操作都是在mnesia_tm进程内进行的。

%执行回滚操作
do_fallback_start(true, false) ->
    verbose("Starting from fallback...~n", []),
    %拿到备份文件
    BupFile = fallback_bup(),
    Mod = mnesia_backup,
    %创建一个ets,用来保存本地表
    LocalTabs = ?ets_new_table(mnesia_local_tables, [set, public, {keypos, 2}]),
    case catch iterate(Mod, fun restore_tables/4, BupFile, {start, LocalTabs}) of
        {ok, _Res} ->
            %%  让dets关闭掉schema
            catch dets:close(schema),
            %% 设置临时的文件为schema.TMP
            TmpSchema = mnesia_lib:tab2tmp(schema),
            %% 设置数据文件为schema.DAT
            DatSchema = mnesia_lib:tab2dat(schema),
            %% 得到所有本地表
              AllLT  = ?ets_match_object(LocalTabs, '_'),
            %关闭ets
              ?ets_delete_table(LocalTabs),
            %% schema.TMP重命名为schema.DAT
            case file:rename(TmpSchema, DatSchema) of
                ok ->
                    %% 除了schema表外,全部进行swap操作
                        [(LT#local_tab.swap)(LT#local_tab.name, LT) ||
                             LT <- AllLT, LT#local_tab.name =/= schema],
                    file:delete(BupFile),
                    ok;
                {error, Reason} ->
                    file:delete(TmpSchema),
                    {error, {"Cannot start from fallback. Rename error.", Reason}}
            end;
        {error, Reason} ->
            {error, {"Cannot start from fallback", Reason}};
        {'EXIT', Reason} ->
            {error, {"Cannot start from fallback", Reason}}
    end.

do_fallback_start函数会进行数据恢复的准备工作,它进行了下面这些工作

  • 建立mnesia_local_tables的ets表,用来保存restore_tables函数在恢复过程中,恢复出本节点内的表的信息
  • 生成schema.DAT文件
  • 生成本节点内所有表的.DAT文件,.DCL文件和.DCD文件

restore_tables函数

restore_tables函数依旧是依赖mnesia_bup的通用函数iterate,将FALLBACK.BUP文件中的schema数据和表项目数据读取出来,并逐条遍历。

restore_tables函数会有几个状态,这几个状态分别是

  • {start, LocalTabs},从FALLBACK.BUP中读取schema信息,根据表信息构建local_tab这个record,并保存到mnesia_local_tables中,为了可以在后面的恢复操作中使用
  • {new, LocalTabs} ,开始各表的数据恢复,会对FALLBACK中的数据项的record名和mnesia_local_tables的table名称进行比对,从而决定是恢复数据还是忽略
  • {not_local, LocalTabs, Tab},如果在mnesia_local_tables查找不到对应的表名称的时候,就会进入此状态,这个过程中读取的数据会全部忽略掉
  • {local, LocalTabs, LT},在mnesia_local_tables中查找到对应表明,进入此状态,进行数据恢复

init_dat_files函数

init_dat_files是restore_tables在构建mnesia_local_tables中项目的重要函数。

它的主要工作有:

  • 根据schema提供的信息生成local_tab的record,包括schema表自身的信息
  • 创建除了schema表外所有的表的数据文件

在仔细观察这个函数会发现,针对存储类型为disc_only_copies的表会建立一个dets,而对ram_copies和disc_copies类型存储的表只会建立.DCL日志存储和.DCD存储。存储方式的不同直接影响到了Mnesia如何读取数据和管理数据,在后面的文章将逐步分析相关内容。

总结

从整个过程中,可以看到Mnesia创建schema的过程后半段不仅仅可以创建一个schema.DAT文件,而且能创建包含数据的表。同时可以看出,Mnesia的Schema.DAT就是一个dets文件,完全可以简单的创建出来,但是这个过程确大费周章。当然这样做是有很大的原因的,这就需要考察Mnesia的备份机制和远程安装数据的机制了,在分析完Mnesia的启动和读写过程后,将会逐步对相关机制展开分析。

暂无回复。
需要 登录/注册 后方可回复, 如果你还没有账号请点击这里 注册