Mnesia:如何同时锁定多行,以便我可以写入/读取一组“一致”的记录

2024-05-09

我多么希望我一开始就能表达我的问题

取一个包含 26 个键 a-z 的表,并让它们具有整数值。 创建一个流程,哎哟,一遍又一遍地做两件事

  1. 在一笔交易中,写入随机值a, b, and c使得这些值always总和为 10
  2. 在另一个事务中,读取值a, b and c如果它们的值之和不等于 10 则抱怨

如果您启动其中的几个进程,您很快就会发现a, b and c处于其值之和不等于 10 的状态。我相信没有办法要求 mnesia“锁定这 3 条记录before开始写入(或读取)”,只能让 mnesia 在到达记录时锁定记录(可以这么说),这允许记录集的值违反我的“总和必须为 10”约束。

如果我是对的,这个问题的解决方案包括

  1. 在写入(或读取)3 条记录集之前锁定整个表——我讨厌锁定整个表 3 条记录,
  2. 创建一个进程来跟踪谁正在读取或写入哪些密钥,并保护批量操作不被其他人写入或读取,直到操作完成。当然,我必须确保所有进程都使用这个...废话,我想这意味着编写我自己的 AccessMod 作为 Activity/4 的第四个参数,这似乎是一个不平凡的练习
  3. 还有一些事情我不够聪明,无法弄清楚。

想法?

好吧,我是一个雄心勃勃的 Erlang 新手,如果这是一个愚蠢的问题,我很抱歉,但是

我正在构建一个特定于应用程序的内存中分布式缓存,并且我需要能够编写一组核心价值在一笔交易中配对,并在一笔交易中检索一组值。换句话说,我需要 1)写40核心价值配对到缓存中,并确保在此多键写入操作期间没有其他人可以读取或写入这 40 个键中的任何一个;和, 2) 在一次操作中读取 40 个键,并返回 40 个值,知道从该读取操作开始到结束,所有 40 个值都没有变化。

我能想到的唯一方法是在 fetch_keylist([ListOfKeys]) 开头或 write_keylist([KeyValuePairs] 开头锁定整个表,但我不想这样做,因为我有许多进程同时进行自己的多键读取和写入,并且我不想在任何进程需要读取/写入相对较小的记录子集时锁定整个表。

Help?

试着说得更清楚:我不认为这只是使用普通交易

I think我问的是一个比这更微妙的问题。想象一下,我有一个流程,在一个事务中迭代 10 条记录,并在运行过程中锁定它们。现在想象这个过程开始,但在迭代到第三条记录之前,另一个过程更新了第三条记录。就事务而言,这很好,因为第一个进程尚未锁定第三条记录,而其他进程在第一个进程到达它之前修改了它并释放了它。我想要的是保证一旦我的第一个过程starts在第一个进程处理完这 10 条记录之前,没有其他进程可以访问它们。

问题已解决 - 我是个白痴...我想... 感谢所有患者,特别是 Hynek -Pichi- Vychodil! 我准备了测试代码来显示问题,并且我could事实上重现了这个问题。然后我简化了代码以提高可读性,问题就消失了。我无法再次重现该问题。这对我来说既尴尬又神秘,因为我已经有这个问题好几天了。而且 mnesia 从来没有抱怨过我在事务之外执行操作,并且我的代码中没有脏事务,我不知道如何能够将这个错误引入到我的代码中!

我已经把孤立的概念深深地印在了我的脑海里,并且不会怀疑它再次存在。

感谢您的教育。

实际上,问题出在 mnesia 操作上使用 try/catchwithin一笔交易。看here https://stackoverflow.com/questions/8099261/unintentionally-intercepting-mnesias-transactional-retries-with-try-catch-rook了解更多。


Mnesia 交易正是为你做这件事。这就是事务的用途,除非你做了肮脏的操作。因此,只需将写入和读取操作放入一个事务中,mnesia 就会完成其余操作。一个事务中的所有操作都作为一个原子操作完成。 Mnesia 事务隔离级别有时称为“可串行化”,即最强的隔离级别。

Edit:

看来你错过了关于 Erlang 并发进程的一个重要观点。 (公平地说,这不仅在 Erlang 中如此,而且在任何真正的并发环境中都是如此,当有人争论时,这不是真正的并发环境。)除非您进行一些同步,否则您无法区分哪个操作首先发生,哪个操作第二个发生。实现此同步的唯一方法是使用消息传递。关于 Erlang 中的消息,您只能保证一件事,即从一个进程发送到另一进程的消息的顺序。这意味着当您发送两条消息时M1 and M2从过程A处理B他们以相同的顺序到达。但如果你发消息M1 from A to B和留言M2 from C to B他们可以按任何顺序到达。只是因为您如何知道您先发送了哪条消息?如果你发消息那就更糟糕了M1 from A to B进而M2 from A to C什么时候M2到达C send M3 from C to B你没有保证这一点M1到达B before M3。即使在当前实施中,它也会发生在一台虚拟机中。但你不能依赖它,因为它没有得到保证,甚至在下一个版本的 VM 中也可能会因为不同调度程序之间的消息传递实现而发生变化。

它说明了并发进程中的事件排序问题。现在回到 mnesia 事务。 Mnesia 交易必须无副作用fun。这意味着可能没有任何消息从交易向外发送。所以你无法判断哪个事务首先开始以及何时开始。您唯一能判断交易是否成功的事情是,他们命令您只能根据其效果来确定。当你考虑到这一点时,你微妙的澄清就毫无意义了。即使在事务实现中是一个一个地读取一个键,一个事务也会以原子操作的方式读取所有键,并且您的写操作也将作为原子操作执行。您无法判断在第一个事务中读取第一个密钥后是否发生了对第二个事务中的第四个密钥的写入,因为从外部无法观察到它。两个事务都将作为单独的原子操作按特定顺序执行。从外部角度来看,所有密钥都将在同一时间点被读取,这是记忆力强制执行的工作。如果您从事务内部发送消息,则违反了 mnesia 事务属性,并且它会表现得很奇怪,您不会感到惊讶。具体来说,这个消息可以发送多次。

Edit2:

如果您启动其中的几个进程,您会发现非常 很快,a、b 和 c 就处于其值之和不等于 10 的状态。

我很好奇为什么你认为会发生这种情况或者你测试过它?向我展示你的测试用例,我将展示我的测试用例:

-module(transactions).

-export([start/2, sum/0, write/0]).

start(W, R) ->
  mnesia:start(),
  {atomic, ok} = mnesia:create_table(test, [{ram_copies,[node()]}]),
  F = fun() ->
      ok = mnesia:write({test, a, 10}),
      [ ok = mnesia:write({test, X, 0}) || X <-
        [b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]],
      ok
  end,
  {atomic, ok} = mnesia:transaction(F),
  F2 = fun() ->
    S = self(),
    erlang:send_after(1000, S, show),
    [ spawn_link(fun() -> writer(S) end) || _ <- lists:seq(1,W) ],
    [ spawn_link(fun() -> reader(S) end) || _ <- lists:seq(1,R) ],
    collect(0,0)
  end,
  spawn(F2).

collect(R, W) ->
  receive
    read -> collect(R+1, W);
    write -> collect(R, W+1);
    show ->
      erlang:send_after(1000, self(), show),
      io:format("R: ~p, W: ~p~n", [R,W]),
      collect(R, W)
  end.

keys() ->
  element(random:uniform(6),
    {[a,b,c],[a,c,b],[b,a,c],[b,c,a],[c,a,b],[c,b,a]}).

sum() ->
  F = fun() ->
      lists:sum([X || K<-keys(), {test, _, X} <- mnesia:read(test, K)])
  end,
  {atomic, S} = mnesia:transaction(F),
  S.

write() ->
  F = fun() ->
      [A, B ] = L = [ random:uniform(10) || _ <- [1,2] ],
      [ok = mnesia:write({test, K, V}) || {K, V} <- lists:zip(keys(),
          [10-A-B|L])],
      ok
  end,
  {atomic, ok} = mnesia:transaction(F),
  ok.

reader(P) ->
  case sum() of
    10 ->
      P ! read,
      reader(P);
    _ ->
      io:format("ERROR!!!~n",[]),
      exit(error)
  end.

writer(P) ->
  ok = write(),
  P ! write,
  writer(P).

如果它不起作用,那将是一个非常严重的问题。有一些重要的应用程序,包括依赖它的支付系统。如果您的测试用例显示它已损坏,请报告错误[电子邮件受保护] /cdn-cgi/l/email-protection

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mnesia:如何同时锁定多行,以便我可以写入/读取一组“一致”的记录 的相关文章

  • 随机排列列表中的元素(随机重新排列列表元素)

    我的程序的一部分要求我能够随机洗牌列表元素 我需要一个函数 当我给它一个列表时 它会伪随机地重新排列列表中的元素 安排的改变Must每次通话时都可以看到相同的列表 我的实现似乎工作得很好 但我觉得它相当长 并且正在增加我的代码库 而且 我有
  • 对列表中的 Erlang 记录进行排序?

    我在erlang中有一条记录 record myrec id 0 price 0 quantity 0 然后 我有一个记录列表 我想按 id 和价格按降序和升序排序 其中价格是第一个键 如果两个记录具有相同的价格 我想按 id 对它们进行排
  • 如何返回元素的个数?

    我必须编写一个函数 它接受一个整数列表作为参数并返回列表中小于 1 的整数的数量 到目前为止 我所拥有的是一个仅返回列表中的整数个数的函数 我不确定应该在哪里 是否放置 if 语句和计数器以仅返回有多少个整数小于 1 export num
  • ejabberd 和 Erlang 安装,lager_transform 未定义

    我是 Erlang 新手 我一直在尝试在 EC2 ubuntu 机器上安装 Erlang 和 ejabberd 一切都很顺利 直到我开始编译一些外部模块ejabberd 它开始抛出错误undefined parse transform la
  • 使用字符串将 Erlang 映射编码为 JSON 以便通过 Javascript 进行解析?

    我正在尝试使用 Erlang 地图 例如 breakfast gt leftovers 并编码为 JSON 映射 例如 我尝试使用 jiffy 转换列表 email protected cdn cgi l email protection
  • 零部署 CouchDB 嵌入 Windows 应用程序?

    我可能在这里做梦 但我想知道是否有可能将最小的 CouchDB 引擎完全嵌入到 Windows 应用程序中 以便该应用程序可以运行而无需在用户计算机上安装 CouchDB Erlang 我已经提供了这种精简 捆绑的功能 请在此处查看http
  • Erlang:如何限制分配给进程的内存

    我要问的是是否可以限制分配给特定进程的内存 堆或堆栈 以便该进程不能超过它 也许类似于 process flag min heap size MinHeapSize 但针对最大堆 您可以将某种进程跟踪 gen server 放在一起 定期检
  • 在erlang中打印数字的每个数字的问题

    我正在尝试编写一个程序 该程序将读入一个数字 然后将该数字的每个数字输出到列表中 然而 在我尝试使用数字 8 和 9 之前 大多数事情看起来都很好 该程序仅输出 b t反而 如果输入的数字包含8或9 同时还有其他数字 例如283 就可以正常
  • 如何使用 ibrowse 将附件上传到 CouchDB 中的文档?

    我已经使用curl上传图像文件Penguins jpg 例如 C curl gt curl vX PUT H Content Type image jpeg http localhost 5984 DBNAME DOCID Penguins
  • 将 erlang shell 作为守护进程/服务运行

    显然 我有一个在 Erlang shell 中运行的 Erlang 程序 我想监视它 这就是我要的 当机器启动时 Erlang shell 应该随之启动 并且在 shell 中运行的程序也应该随之启动 如果 Erlang shell 由于某
  • Erl 无法连接到本地 EPMD。为什么?

    Erlang R14B04 erts 5 8 5 source 64 bit rq 1 async threads 0 kernel poll false Eshell V5 8 5 abort with G root ip 10 101
  • Erlang:如何将小数转换为填充零的十六进制字符串

    我想在 Erlang 中将 42 基数 10 转换为 000002A 基数 16 我在网上找到了一些提示 io format 8 0B n 42 gt 00000042 And io format 16B n 42 gt 2A 但我似乎无法
  • 如何修改erlang中的记录?

    我需要修改操作记录中的值 place 和 other place op action walk from place to other place preconds at place me on floor me other place p
  • 当通过 basho rebar 从命令行运行 Erlang 应用程序时,如何设置 Erlang 节点名称

    我已经使用 basho rebar 编译了我的 Erlang 应用程序 它生成了一个独立的 escript 可执行文件 我从命令行运行它 如下所示 myapp myconfig config 我的问题是如何确定运行我的应用程序的 Erlan
  • Erlang Mnesia 中的分页搜索

    例如 给定记录 record item id time status 我想搜索 1000 到 1100 个项目 按时间和顺序排序status lt lt finished gt gt 有什么建议么 这取决于您的查询是什么样的 如果您需要按许
  • 如何在 Erlang 中将数字转换为单词?

    我发现了一个关于将数字转换为 单词 的有趣问题 代码高尔夫 数字到单词 https stackoverflow com questions 309884 code golf number to words 我真的很想看看你如何在 Erlan
  • Erlang gen_tcp 连接问题

    简单的问题 这段代码 client gt SomeHostInNet localhost to make it runnable on one machine ok Sock gen tcp connect SomeHostInNet 56
  • 如何在erlang中读取mnesia数据库的所有记录?

    我是 erlang 新手 我需要对从 mnesia 数据库获取的所有记录进行一些操作 Result mnesia dirty read mydatabase key1 key2 case Result of gt DEBUG No such
  • Erlang:将元素“添加到元组之前”

    是否可以编写一个与此函数等效的更快的函数 prepend X Tuple gt list to tuple X tuple to list Tuple 在我看来 这种事情是不被鼓励的 如果您想要一个列表 请使用一个 Erlang 入门 ht
  • Erlang 进程如何(如果有的话)映射到内核线程?

    Erlang 因能够支持许多轻量级进程而闻名 它之所以能做到这一点 是因为它们不是传统意义上的进程 甚至不是 P 线程中的线程 而是完全在用户空间中的线程 这很好 实际上很棒 那么 Erlang 线程如何在多核 多处理器环境中并行执行呢 当

随机推荐

  • 如何检测 JSF 应用程序中的客户端区域设置?

    我该如何使用ServletRequest getLocale 在 JSF 应用程序中 当Servlet我的代码中不存在并且由 JSF 实现提供 我正在尝试使用ServletContextListener 但是有可能达到ServletRequ
  • 使轮子在IE中旋转

    我有以下使用 JS 和 CSS 旋转轮子的代码 var prefix function if document body style MozTransform undefined return MozTransform else if do
  • Angular:使用 @ContentChildren 让子组件进入另一个组件

    我在 Angular 6 中创建了一个自定义轮播组件 简单用法如下
  • JMenuItems 在 JLayeredPane 中的较高组件上绘制

    我在 JLayeredPane 的一层上的 JPanel 中有一组 JMenuItem 并在更高层的 JPanel 中绘制了一个模拟光标 当菜单项重新绘制时 它们会在模拟光标上绘制 不会触发光标层的重新绘制 有趣的是 如果我用 JButto
  • 如何在 Angular-4 中的 md-progress-spinner 中设置文本

    在 Angular 4 中 我像这样设置进度旋转器
  • 重复的 AssemblyVersion 属性

    我有一个项目在编译时生成以下错误 错误 CS0579 重复的 AssemblyVersion 属性 我已经检查过文件AssemblyInfo cs看起来那里没有重复 I found MSDN 上的这篇文章 http social msdn
  • ListView onClick 事件不会因链接的电子邮件地址而触发

    我有一个直接的 ListView 带有 ListAdapter 和列表的自定义 onItemClick 方法 我的 ListView 项目可单击以执行其他功能 但是 我的一些 ListView 元素包含一个电子邮件地址should也可以点击
  • 如何读取 Google 表格中单元格的颜色

    我正在使用 Python Google Sheets API 并且我想读取单个单元格的颜色 我已阅读文档 但我只能找到有关如何从单元格检索文本的信息 而不是颜色格式的信息 您可以使用方法 电子表格 get https developers
  • 终端中的 Visual Studio Code Java 路径

    我刚刚开始使用 Visual Studio Code 并用 Java 创建了一个简单的 Hello World 程序 它打印Hello World就像它应该的那样 但我也得到了一些路径 例如 usr lib jvm java 11 open
  • R 中有没有快速替换列值的方法?

    假设我们有一个包含数值的数据框 如下所示 Temperature Height 32 157 31 159 33 139 我想更换Height价值观与pic 00001 pic 00002等等 最终结果是 Temperature Heigh
  • Java:getTimeZone不返回默认值

    我有以下指示 TimeZone zone TimeZone getTimeZone Asia Toyo 显然 它应该返回 null 但它会返回默认时区 这不是我的情况所需的行为 来自 Java 文档 返回指定的TimeZone 或 GMT
  • 为什么超过44个字符时打印随机符号

    我正在从 C 编程 现代方法 一书中学习 C 现在我正在进行有关数组的练习 练习之一是编写一个过滤器 以不同的方式打印输入消息 到目前为止 参见下面的代码 一切正常 直到字符数超过 44 然后它打印随机符号 如果字符数低于 44 则一切正常
  • 如何在 firebase 中设置重复项目? [复制]

    这个问题在这里已经有答案了 我想在 firebase 中创建一个重复的项目 这样我就不必经历添加 firebase 功能和通知等的麻烦 如果可以的话 我会删除所有身份验证用户 以便为实际的应用程序做好准备 但我无法做到这一点 那么 如何在没
  • 使用什么来生成包含动态生成的条形码的 pdf 文档(Java)?

    我的要求要求生成包含任意文本和条形码的 pdf 文档 我有相关的question https stackoverflow com q 6625849 59470它解决了pdf生成部分 但在这里我想知道如何在Java中将条形码合并到pdf中
  • Find() 的 Javascript 代码优化

    我有 C 代码 可以在 SQL 中运行查询并返回大约 2000 行 然后创建一个Treeview控件并添加到我的主页 这几乎是立即完成的 这很好 var orgId select name ctl00 PageContent Functio
  • 如何更改 Google 表格中图表的背景不透明度?

    我想在 Google 表格中设置 Google 图表的透明度或不透明度 就像在 Microsoft Excel 中一样 将图像设置在文本后面 以便文本仍然可读 不过好像该功能不起作用 功能预览 http drive google com f
  • 保存到服务器后,隐藏字符“\u0”添加到文件中

    我正在使用 Apache 服务器为 Web 开发网站提供服务 这样我就可以不断保存和编辑文件 我使用 Gulp for Sass 来连接和丑化 css 和 js 文件 一个月前 我的 js 和 css 文件遇到问题 似乎在文件下面添加了随机
  • 在Web应用程序中调用phonegap插件功能

    我正在构建我的第一个phonegap应用程序 当我打开该应用程序时 我立即将用户重定向 window location 到托管我的网络应用程序的服务器 是否可以从那里加载phonegap 插件 因为 deviceready 事件没有触发 我
  • PIL 不保存透明度

    from PIL import Image img Image open 1 png img save 2 png 第一张图像具有透明背景 但是当我保存它时 透明度消失了 背景为白色 我究竟做错了什么 可能图像已被索引 PIL 中的模式 P
  • Mnesia:如何同时锁定多行,以便我可以写入/读取一组“一致”的记录

    我多么希望我一开始就能表达我的问题 取一个包含 26 个键 a z 的表 并让它们具有整数值 创建一个流程 哎哟 一遍又一遍地做两件事 在一笔交易中 写入随机值a b and c使得这些值always总和为 10 在另一个事务中 读取值a