【问题标题】:How can I implement a lossless CRDT using Gun?如何使用 Gun 实现无损 CRDT?
【发布时间】:2019-02-05 06:04:03
【问题描述】:

如何使用 Gun 创建 CRDT?

例如,如果我想实现一个只增长的数组,其中每个元素都指向下一个元素,我该如何解决冲突?

为简化起见,让我们创建一个 Alice 和 Bob 合作的场景。

该数组包含 3 个元素,[a, b, d]

这个数组的内部表示是这样的链表:

a => b => c

(当然,内部表示形式类似于{value: 'a', next: { value: 'b' next: { value: 'c' }}}),但我认为您使用更简洁的符号表示我的意思。

Alice 现在想在 bd 之间插入元素 c

同时,Bob 想要在 bd 之间插入元素 C

同时,它们具有数组的这种内部表示:

爱丽丝:a => b => c => d

鲍勃:a => b => C => d

当他们加入 CRDT 时,他们会收敛到以下任一值:

a => b => c => C => d

a => b => C => c => d

无论如何,a) 它们都会收敛到相同的值,并且 b) 它们不会丢失彼此的数据。

我们可以使用 Gun 实现这一点吗?

(本题是对https://github.com/amark/gun/issues/602的简化和后续问题)

【问题讨论】:

    标签: gun crdt


    【解决方案1】:

    是的。

    这是几年前的代码演示:

    https://youtu.be/rci89p0o2wQ

    您可以在 GUN 的基础 CRDT 之上创建任何其他 CRDT 作为数据结构。

    我们甚至对这类东西的通用算法做了一个完整的卡通解释:

    https://gun.eco/explainers/school/class.html

    (或查看针对特定案例的实现的更详细说明,由精彩的 Martin Kleppmann 撰写,从 https://youtu.be/yCcWpzY8dIA?t=29m36s 开始)

    我还没有看到有人专门在 GUN 之上实现 RGA,但考虑到您发送的代码有多短,应该很容易。 (虽然“删除”需要是空墓碑,但这很好)

    从查看计数器 CRDT 开始可能是最简单的方法,“如何开始使用自定义扩展将数据保存到 GUN”,仅 12 行代码即可增长的 CRDT:

    https://gun.eco/docs/Counter

    你注意到它非常基础,RGA 也差不多,你可能会有一些 GUN 扩展(只是一个 JS 方法/函数,让开发人员更容易使用),比如

    Gun.chain.rga = function(...

    然后在内部,就像使用计数器一样,您可以调用 gun.put(gun.set( 或任何其他命令来将数据保存到图形中(put 和 set 本身只是 RGA 的扩展,这里没什么特别的) 'd build/construct a graph/tree/table, or you could be lazy and just do something like:

    // fictional code
    var myData = {
      rgaTree: {left: {}, right: {}}
    }
    myData.rgaTree.left.next = myData.rgaTree.right;
    myData.rgaTree.right.prev = myData.rgaTree.left;
    // yes! circular references are supported!
    gun.put(myData);
    

    显然,您可能希望更详细并使用 cuid 和其他东西来控制 UUID,但您明白了。

    没有理由直接直接替换 HAM CRDT 或“注入”一个 CRDT,只是 @pgte 会在 GUN 上建模 CRDT 的数据结构(可能通过 GUN 扩展使用一个很好的简单 API),然后你' d 还让该扩展支持回调,如果通过 RGA 图/树传递 gun.get(... 并运行各种 RGA 逻辑,然后将结果返回给开发人员。这棵树可以在 GUN 内部被许多对等方同时动态变异,比如 Alice 和 Bob!

    然后,GUN 将通过(许多)存储引擎之一(例如 IPFS!)将动态更改和更新的数据保存到磁盘,因此 IPFS 可以随着时间的推移托管数据的持久性,而 GUN 可以管理 O(1)树查找是可变/变化/动态的树/图/索引结构。

    【讨论】:

    • 嗨,马克,感谢您的回复。我在这里有点困惑,希望你能帮助我。如果我使用.set,我会将项目添加到集合中。相反,如果我使用.put,我将覆盖数据,并且我将让最后一个作家获胜。这是正确的吗?
    • @pgte 是的。一些极端情况:.set(gunRef) 使用 gunRef ID 对集合中的项目进行去重(适当的数学集合)。 .set(data) 如果数据不是 gunRef 则很难判断行为应该是什么,因此它使用基本 36 时间戳作为 ID,因此您可以根据它“松散地”对项目进行排序,将其添加到“表” . .set 是建立在 .put 之上的,就像 .set(data) = .get(id).put(data) 一样。 .put 是核心操作,它更新/变异/更改/合并属性上的数据(除非该属性上的值是原子的,否则它不会覆盖)。由 CRDT 确定的“最后一个”写入获胜,而不是任何人的“最后一个”。
    • 好的。据我所知,这意味着我不能将 RGA 建模为链表,而是作为集合的集合。 RGA 通过保留以下集合来工作:
    • 向量中的每个元素都有一个id。
    • * id 映射 => 值
    猜你喜欢
    • 2021-12-18
    • 2013-06-15
    • 2019-11-25
    • 2022-10-16
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 2021-01-24
    相关资源
    最近更新 更多