上一篇博文介绍了mnesia的锁请求过程,在请求到锁后,mnesia:write将更新写入临时ets表,此后mnesia:write将完成其使命,重新回到mnesia_tm:apply_fun函数中,此后将继续分析。
apply_fun(Fun, Args, Type) ->
Result = apply(Fun, Args),
case t_commit(Type) of
do_commit ->
{atomic, Result};
do_commit_nested ->
{nested_atomic, Result};
{do_abort, {aborted, Reason}} ->
{'EXIT', {aborted, Reason}};
{do_abort, Reason} ->
{'EXIT', {aborted, Reason}}
end.
Type参数为async
t_commit(Type) ->
{_Mod, Tid, Ts} = get(mnesia_activity_state),
Store = Ts#tidstore.store,
if
Ts#tidstore.level == 1 ->
intercept_friends(Tid, Ts),
%% N is number of updates
case arrange(Tid, Store, Type) of
{N, Prep} when N > 0 ->
multi_commit(Prep#prep.protocol,
majority_attr(Prep),
Tid, Prep#prep.records, Store);
{0, Prep} ->
multi_commit(read_only,
majority_attr(Prep),
Tid, Prep#prep.records, Store)
end;
...
end.
在进行事务提交前,需要为每个事务参与结点计算其更新内容。
arrange(Tid, Store, Type) ->
Nodes = get_elements(nodes,Store),
Recs = prep_recs(Nodes, []),
Key = ?ets_first(Store),
N = 0,
Prep =
case Type of
async -> #prep{protocol = sym_trans, records = Recs};
sync -> #prep{protocol = sync_sym_trans, records = Recs}
end,
case catch do_arrange(Tid, Store, Key, Prep, N) of
{'EXIT', Reason} ->
dbg_out("do_arrange failed ~p ~p~n", [Reason, Tid]),
case Reason of
{aborted, R} ->
mnesia:abort(R);
_ ->
mnesia:abort(Reason)
end;
{New, Prepared} ->
{New, Prepared#prep{records = reverse(Prepared#prep.records)}}
end.
临时ets表的nodes就是之前请求锁的目的结点,它们都是事务参与结点,此时事务提交类型为异步,其事务提交协议为sym_trans,及异步同构事务。
prep_recs([N | Nodes], Recs) ->
prep_recs(Nodes, [#commit{decision = presume_commit, node = N} | Recs]);
prep_recs([], Recs) ->
Recs.
从临时ets表中取得所有的表操作记录,根据这些表操作,为每个事务参与结点构建一个事务提交结构commit并进行填充。
do_arrange(Tid, Store, {Tab, Key}, Prep, N)
->
Oid = {Tab, Key},
Items = ?ets_lookup(Store, Oid), %% Store is a bag
P2 = prepare_items(Tid, Tab, Key, Items, Prep),
do_arrange(Tid,
Store, ?ets_next(Store, Oid), P2, N + 1);
prepare_items(Tid, Tab, Key, Items, Prep)
when Prep#prep.prev_tab == Tab ->
Types = Prep#prep.prev_types,
Snmp = Prep#prep.prev_snmp,
Recs = Prep#prep.records,
Recs2 = do_prepare_items(Tid, Tab, Key, Types,
Snmp, Items, Recs),
Prep#prep{records = Recs2};
prepare_items(Tid, Tab, Key, Items, Prep)
->
Types = val({Tab, where_to_commit}),
case Types of
[]
-> mnesia:abort({no_exists, Tab});
{blocked,
_} ->
unblocked = req({unblock_me, Tab}),
prepare_items(Tid, Tab, Key, Items, Prep);
_
->
Majority = needs_majority(Tab, Prep),
Snmp = val({Tab, snmp}),
Recs2 = do_prepare_items(Tid,
Tab, Key, Types,
Snmp, Items, Prep#prep.records),
Prep2 = Prep#prep{records = Recs2, prev_tab
= Tab,
majority = Majority,
prev_types = Types, prev_snmp = Snmp},
check_prep(Prep2, Types)
end.
构建事务提交的准备结构,将同一个表的操作合并在一起。
do_prepare_items(Tid, Tab, Key, Types, Snmp, Items, Recs) ->
Recs2 = prepare_snmp(Tid, Tab, Key, Types, Snmp, Items, Recs), % May exit
prepare_nodes(Tid, Types, Items, Recs2, normal).
prepare_nodes(Tid, [{Node, Storage} | Rest], Items, C, Kind) ->
{Rec, C2} = pick_node(Tid, Node, C, []),
Rec2 = prepare_node(Node, Storage, Items, Rec, Kind),
[Rec2 | prepare_nodes(Tid, Rest, Items, C2, Kind)];
prepare_nodes(_Tid, [], _Items, CommitRecords, _Kind) ->
CommitRecords.
prepare_nodes根据表的where_to_commit属性进行处理,该表属性为一个{Node,StorageType}列表。
pick_node(Tid, Node, [Rec | Rest], Done) ->
if
Rec#commit.node == Node ->
{Rec, Done ++ Rest};
true ->
pick_node(Tid, Node, Rest, [Rec | Done])
end;
pick_node({dirty,_}, Node, [], Done) ->
{#commit{decision = presume_commit, node = Node}, Done};
pick_node(_Tid, Node, [], _Done) ->
mnesia:abort({bad_commit, {missing_lock, Node}}).
pick_node为一个事务参与结点整理出表的操作,形成{NodeCommit, Ops}元组
prepare_node(Node, Storage, [Item | Items], Rec, Kind) when Kind == snmp ->
Rec2 = Rec#commit{snmp = [Item | Rec#commit.snmp]},
prepare_node(Node, Storage, Items, Rec2, Kind);
prepare_node(Node, Storage, [Item | Items], Rec, Kind) when Kind /= schema ->
Rec2 =
case Storage of
ram_copies ->
Rec#commit{ram_copies = [Item | Rec#commit.ram_copies]};
disc_copies ->
Rec#commit{disc_copies = [Item | Rec#commit.disc_copies]};
disc_only_copies ->
Rec#commit{disc_only_copies = [Item | Rec#commit.disc_only_copies]}
end,
prepare_node(Node, Storage, Items, Rec2, Kind);
prepare_node(_Node, _Storage, Items, Rec, Kind)
when Kind == schema, Rec#commit.schema_ops == [] ->
Rec#commit{schema_ops = Items};
prepare_node(_Node, _Storage, [], Rec, _Kind) ->
Rec.
prepare_node根据事务参与结点的存储类型,进一步将表操作填充到事务参与结点的commit结构的具体存储类型中
t_commit(Type) ->
{_Mod, Tid, Ts} = get(mnesia_activity_state),
Store = Ts#tidstore.store,
if
Ts#tidstore.level == 1 ->
intercept_friends(Tid, Ts),
case arrange(Tid, Store, Type) of
{N, Prep} when N > 0 ->
multi_commit(Prep#prep.protocol, majority_attr(Prep), Tid, Prep#prep.records, Store);
{0, Prep} ->
multi_commit(read_only, majority_attr(Prep), Tid, Prep#prep.records, Store)
end;
...
end.
不考虑嵌套事务的情况,此时,已经为每个事务参与结点构建了一个commit结构,该结构根据事务参与结点的存储类型,在ram_copies、disc_copies、disc_only_copies之一中记录了所有的表操作记录。
事务提交准备过程需要根据此前的更新情况,为每个事务参与结点构造好commit结构,该结构记录了在结点的具体副本类型下需要进行的更新,在下一步的提交过程中,将向各个事务参与结点传递该结构,以完成提交。
未完待续...
分享到:
相关推荐
session, specify a Mnesia database directory, initialize a database schema, start Mnesia, and create tables. Initial prototyping of record definitions is also discussed. • Build a Mnesia Database ...
在分析 Mnesia 表分片的过程和算法之前,首先要理解分片的必要性和它所解决的问题。随着业务的发展,数据量会迅速增加,读写请求的次数也会大幅增长。为了保证服务的高可用性,系统需要能够在短时间内处理大量的读写...
AMNESIA还提供了事务支持,确保了数据的一致性和完整性,这对于在分布式环境中运行的应用程序至关重要。 AMNESIA的另一个核心特性是其强大的查询功能。虽然它不直接使用SQL,但提供了类似查询构建器的工具,允许...
B站视频地址: 做了文字校验,已经成功上线,有兴趣的小伙伴可以扫码体验:可以微信搜索:失忆备忘录一、失忆的由来之所以开发这款软件,是因为在那段时间事情很多,但是经常忘记。虽然市面上类似的功能很多,我之前...
《Mnesia用户手册》是专为理解和操作Erlang编程语言中的Mnesia数据库管理系统而编写的详尽指南。Mnesia是Erlang OTP (Open Telephony Platform) 库中的一个核心组件,它是一个强大的分布式数据库系统,特别适用于...
Api-Social-Amnesia.zip,忘记过去。社交健忘症确保你的社交媒体帐户只显示你最近的历史,而不是5年前“那个阶段”的帖子。,一个api可以被认为是多个软件设备之间通信的指导手册。例如,api可用于web应用程序之间的...
8.附录.A:Mnesia.错误信息 8.1.Mnesia.中的错误 9.附录.B:备份回调函数接口 9.1.Mnesia.备份回调行为 10.附录.C:作业存取回调接口 10.1.Mnnesia.存取回调行为 11.附录.D:分片表哈希回调接口 11.1....
语言:English (United States) 遗忘的延伸 Chrome失忆症是一个Chrome扩展程序,可让您有选择地不记得自己的任何浏览历史记录。...有关更多信息,请访问https://github.com/DanielBok/chrome-amnesia。
失忆症是一种提醒,允许您定义警报,贴纸(贴子)以提醒您一些重要的内容以及有关所需内容的注释。 可以将警报编程为在给定时间显示,可以在桌面上放置贴纸以随时查看。
4. **事务处理**:Mnesia支持原子性、一致性、隔离性和持久性(ACID)事务,确保了数据操作的可靠性和一致性。 5. **模式定义**:Mnesia允许用户定义数据库模式,包括表、索引和属性等,提供了一种结构化的方式来...
在事务和上下文访问方面,Mnesia提供了事务属性定义、锁机制、脏操作、记录名与表名映射、作业概念、嵌套事务、模式匹配、迭代等高级功能,支持复杂的数据库操作。 Mnesia的系统信息部分涵盖了数据库配置数据、内核...
- **事务属性**:Mnesia 提供事务处理,确保数据的原子性和一致性。事务可以包含一系列操作,这些操作作为一个单元执行,要么全部成功,要么全部回滚。 - **锁**:为了管理并发访问,Mnesia 使用锁机制来控制对...
8 附录 A : Mnesia 错误信息 . . .. . . 75 8.1 Mnesia 中的错误 . . . . .. . 75 9 附录 B :备份回调函数接口 . . .. . .. . . .. . 76 9.1 Mnesia 备份回调行为 . . .. . . . .. . 76 10 附录 C :作业存取...
#### 四、Mnesia的技术细节 **1. 数据一致性模型** - Mnesia 支持多种数据一致性模型,包括最终一致性(eventual consistency)、强一致性(strong consistency)等,允许开发者根据具体应用需求选择最合适的一致...
"Amnesia"是一个可能与计算机安全或数据丢失相关的主题,暗示了系统或用户可能遭遇了某种形式的记忆丧失,即数据无法访问或丢失的情况。在IT领域,这种情况通常涉及到磁盘故障、病毒攻击、误操作或者软件错误。"Post...