日期:2014-05-16  浏览次数:20472 次

mnesia的普通transaction写过程(一)事务准备

erlang的分布式数据库mnesia是erlang分布式体系中非常重要的组件,其本身具有分布式的特性,可以在多个结点上建立数据副本,支持数据持久化,用好了mnesia,可以极大的减轻分布式架构的设计难度。

本博文带来的第一篇有关mnesia的分析,即是mnesia最常见也最重要的接口:transaction写过程。mnesia的文档上记载(http://www.erlang.org/doc/apps/mnesia/Mnesia_chap4.html#id73876),mnesia包含5种访问上下文,访问上下文没有固定的概念,就我的理解是指,mnesia的操作如read、write等维持事务ACID特性及分布式化的程度,这5种访问上下文分别为:

transaction:普通事务,数据更新满足事务的 ACID?特性,也会同步扩散到所有包含数据副本的mnesia结点,但事务提交时不要求各个副本结点的日志存储在磁盘上;

sync_transaction:完全同步事务,基本过程等同于transaction,但事务提交时各个副本结点的日志均已存储在磁盘上;

async_dirty:dirty_*操作的访问上下文,数据的更新不满足事务的 ACID?特性,更新的数据会异步的复制到其它副本结点;

sync_dirty:类似于async_dirty,但是直到数据完全复制到其它副本上,写操作才会返回;

ets:无任何事务及分布式特性,mnesia是通过ets和dets实现的,数据存储在这些表内,ets上下文指明mnesia仅更新本地ets表。

定义mnesia的表user:

mnesia:create_table(user, [{record_name, user},{attributes, [name, id]},{disc_copies, [node()]}]).

本文将就一条普通的mnesia语句mnesia:transaction(fun() -> mnesia:write({user, me, 12345}) end).进行分析,mnesia版本为4.5.1,揭示mnesia的事务原理。


mnesia.erl

transaction(Fun) ->

transaction(get(mnesia_activity_state), Fun, [], infinity, ?DEFAULT_ACCESS, async).

transaction(State, Fun, Args, Retries, Mod, Kind)

? when is_function(Fun), is_list(Args), Retries == infinity, is_atom(Mod) ->

? ? ?mnesia_tm:transaction(State, Fun, Args, Retries, Mod, Kind);

mnesia:transaction通过mnesia_tm:transaction实现,Mod参数为mnesia,Kind参数为async。


mnesia_tm.erl

transaction(OldTidTs, Fun, Args, Retries, Mod, Type) ->

? ? Factor = 1,

? ? case OldTidTs of

undefined -> % Outer

? ?execute_outer(Mod, Fun, Args, Factor, Retries, Type);

{_, _, non_transaction} -> % Transaction inside ?sync_dirty

? ?Res = execute_outer(Mod, Fun, Args, Factor, Retries, Type),

? ?put(mnesia_activity_state, OldTidTs),

? ?Res;

{OldMod, Tid, Ts} -> ?% Nested

? ?execute_inner(Mod, Tid, OldMod, Ts, Fun, Args, Factor, Retries, Type);

_ -> % Bad nesting

? ?{aborted, nested_transaction}

? ? end.

execute_outer(Mod, Fun, Args, Factor, Retries, Type) ->

? ? case req(start_outer) of

{error, Reas