Skip to content

Commit 920d0fc

Browse files
committed
M src/list/raxos/2d-consensus.md
1 parent 39cc432 commit 920d0fc

12 files changed

+50
-66
lines changed

src/list/raxos/2d-consensus.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Phase-2 append Event 时, 它依赖于所有 Time 小于它的 Event
3030
`Time(xi+yj)` 中, 显然 `x₁ >= x₂ && y₁ >= y₂``T₁ >= T₂`,
3131
`x₁ > x₂ && y₁ < y₂`的情况, 在没有其他条件下是不能比较大小的.
3232

33-
然后我们还需要为Incompatible的History(T)之间定义一个Order, 但为了方便,我们完全可以假定所有History(T)之间有一个全序关系.
33+
然后我们还需要为Incompatible的MonoHistory之间定义一个Order, 但为了方便,我们完全可以假定所有MonoHistory之间有一个全序关系.
3434

3535
但是这个全序关系是什么样子的? 显然任何满足二维向量的偏序关系的Order都可以.
3636

src/list/raxos/Abstract Paxos Diagram.canvas

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@
3434
{"id":"23b19f5ffc793d95","type":"file","file":"consensus-essence/src/list/raxos/def-Apply.md","x":860,"y":50,"width":400,"height":400},
3535
{"id":"82bcd920558f5168","type":"file","file":"consensus-essence/src/list/raxos/desc-Time-in-Distributed.md","x":940,"y":780,"width":400,"height":400,"color":"3"},
3636
{"id":"707de0dee3c23555","type":"file","file":"consensus-essence/src/list/raxos/example-T-in-single-threaded.md","x":1420,"y":780,"width":400,"height":400,"color":"5"},
37-
{"id":"758a0c2db86e743a","type":"file","file":"consensus-essence/src/list/raxos/def-T-History.md","x":315,"y":780,"width":490,"height":300},
37+
{"id":"758a0c2db86e743a","type":"file","file":"consensus-essence/src/list/raxos/def-Mono-History.md","x":315,"y":780,"width":490,"height":300},
3838
{"id":"09a5660b835acde1","type":"file","file":"consensus-essence/src/list/raxos/def-Compatible-History.md","x":-360,"y":2120,"width":400,"height":400},
3939
{"id":"cee5dd045baeea82","type":"file","file":"consensus-essence/src/list/raxos/def-Time-Unique.md","x":-480,"y":680,"width":400,"height":400},
4040
{"id":"7126f3ef8414e0fd","type":"file","file":"consensus-essence/src/list/raxos/def-History-Eq.md","x":-1000,"y":1080,"width":400,"height":400},
4141
{"id":"6d2f40704a61e31b","type":"file","file":"consensus-essence/src/list/raxos/def-History-Prefix.md","x":-170,"y":1432,"width":400,"height":400},
4242
{"id":"9f67b522730e7bd4","type":"file","file":"consensus-essence/src/list/raxos/def-01-Graph.md","x":-1240,"y":1720,"width":400,"height":400},
4343
{"id":"ad67370aed72caab","type":"file","file":"consensus-essence/src/list/raxos/def-Mergeable-History-2.md","x":-840,"y":2760,"width":400,"height":400,"color":"1"},
44-
{"id":"11003bbfc4ff8328","type":"file","file":"consensus-essence/src/list/raxos/def-T-History-PartialOrd.md","x":627,"y":1361,"width":465,"height":238,"color":"1"},
4544
{"id":"056ed53ecdd08e9a","type":"file","file":"consensus-essence/src/list/raxos/def-Distributed-Copies.md","x":360,"y":2232,"width":400,"height":400},
4645
{"id":"ccd61f294c90c33f","type":"file","file":"consensus-essence/src/list/raxos/desc-Time-based-RW.md","x":1960,"y":930,"width":400,"height":400,"color":"3"},
4746
{"id":"e62569bb96739fee","type":"file","file":"consensus-essence/src/list/raxos/def-multiverse.md","x":1384,"y":2920,"width":400,"height":400,"color":"3"},
@@ -53,12 +52,11 @@
5352
{"id":"3f8c8471005eb5fb","type":"file","file":"consensus-essence/src/list/raxos/def-Generic-Commit.md","x":1384,"y":4700,"width":400,"height":400},
5453
{"id":"4425d02ad7c436fc","type":"file","file":"consensus-essence/src/list/raxos/desc-Availability.md","x":1184,"y":5520,"width":400,"height":400,"color":"3"},
5554
{"id":"595a84cdebe4384d","type":"file","file":"consensus-essence/src/list/raxos/def-multiverse-collapse.md","x":1760,"y":6140,"width":400,"height":400},
56-
{"id":"9ad3d014b728235c","x":1834,"y":6869,"width":400,"height":400,"type":"file","file":"consensus-essence/src/list/raxos/def-universe-read.md"},
57-
{"id":"2beb3ad285be0a47","x":1615,"y":7572,"width":400,"height":400,"type":"file","file":"consensus-essence/src/list/raxos/def-write.md"}
55+
{"id":"9ad3d014b728235c","type":"file","file":"consensus-essence/src/list/raxos/def-universe-read.md","x":1834,"y":6869,"width":400,"height":400},
56+
{"id":"2beb3ad285be0a47","type":"file","file":"consensus-essence/src/list/raxos/def-write.md","x":1615,"y":7572,"width":400,"height":400}
5857
],
5958
"edges":[
6059
{"id":"ec72236e30d4ad00","fromNode":"6d2f40704a61e31b","fromSide":"bottom","toNode":"09a5660b835acde1","toSide":"top"},
61-
{"id":"f9f7854203e3206b","fromNode":"758a0c2db86e743a","fromSide":"bottom","toNode":"11003bbfc4ff8328","toSide":"top"},
6260
{"id":"4d07b27b924c85b2","fromNode":"99e03cdec94311b1","fromSide":"bottom","toNode":"758a0c2db86e743a","toSide":"top"},
6361
{"id":"e8175d0d98491650","fromNode":"3bc45c9f8426c1d7","fromSide":"bottom","toNode":"758a0c2db86e743a","toSide":"top"},
6462
{"id":"20052fa07c0e0e75","fromNode":"25beff8f73c32a41","fromSide":"bottom","toNode":"99e03cdec94311b1","toSide":"top"},

src/list/raxos/def-API-read-write.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44

55
我们的系统建立在虚拟时间(Time)、事件(Event)和历史(History)的基础之上。
66
在这个系统中,每个节点可以存储多个 History 值。
7-
一个`History(T)`包含了所有小于等于时间 T 的历史记录,这包括在这些时刻发生的所有 Event 及其依赖关系。
7+
一个`MonoHistory`包含了所有小于等于时间 T 的历史记录,这包括在这些时刻发生的所有 Event 及其依赖关系。
88

99
节点的基本读写接口定义如下:
1010

1111
```rust
1212
impl Node {
13-
fn read(&self) -> Vec<History(T)>;
14-
fn write(&mut self, h: History(T));
13+
fn read(&self) -> Vec<MonoHistory>;
14+
fn write(&mut self, h: MonoHistory);
1515
}
1616
```
1717

1818
根据我们之前的假设,时间 T 是唯一的,不同进程不会产生相同的时间 T。
19-
因此,不会出现两个 History(T) 具有相同的最大时间 T 但内容不同的情况。
19+
因此,不会出现两个 MonoHistory 具有相同的最大时间 T 但内容不同的情况。
2020

2121
write 函数的实现是记录每次写入的 History。
2222
当写入一个新的 History h 时, 不会覆盖以前写入的 History. 系统会同时存储多个 History。如果写入的 History 和现有的 History 有 Prefix 关系, `h ⊑ h_i``h_i ⊑ h`, 则合并.

src/list/raxos/def-RW-Distributed.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Distributed {
1818
histories
1919
}
2020

21-
fn write_to_nodes(&mut self, targets: &[NodeId], h: History(T)) {
21+
fn write_to_nodes(&mut self, targets: &[NodeId], h: MonoHistory) {
2222
for node in targets {
2323
node.write(h);
2424
}

src/list/raxos/def-T-Committed.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
def-T-Committed
22

3-
一个`History({T})` 在T时刻总是能被读到, 即认为它在这个时刻是Committed
3+
一个`MonoHistory` 在T时刻总是能被读到, 即认为它在这个时刻是Committed

src/list/raxos/def-T-History-PartialOrd.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/list/raxos/def-T-History.md

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
## 多重宇宙合并为单一历史
22

33
尽管我们认识到多重历史的存在,但是我们还只是活在单时间线中的低等文明, 我们只能有一个时间线。
4-
这意味着 read() 方法不能返回 `Vec<History(T)>`,而只能返回一个 History,它是由一组相互 Compatible 的 History(T) 合并而成。
4+
这意味着 read() 方法不能返回 `Vec<MonoHistory>`,而只能返回一个 History,它是由一组相互 Compatible 的 MonoHistory 合并而成。
55

66
## read() 合并 History 的职责
77

8-
但是, 因为并不是所有的 History(T) 都是 Compatible 的, 不能直接将所有读到的 History(T)合并.
9-
所以 `read()` 要负责: **在读到的所有 History(T) 中, 任意 2 个不 Compatible 的 History(T)中, 选择其中一个, 舍弃另一个**,
8+
但是, 因为并不是所有的 MonoHistory 都是 Compatible 的, 不能直接将所有读到的 MonoHistory合并.
9+
所以 `read()` 要负责: **在读到的所有 MonoHistory 中, 任意 2 个不 Compatible 的 MonoHistory中, 选择其中一个, 舍弃另一个**,
1010
且选择必须是唯一确定的, 不能是随机的.
11-
最后把所有互相 Compatible 的 History(T) 合并, 作为最终读到的 History.
11+
最后把所有互相 Compatible 的 MonoHistory 合并, 作为最终读到的 History.
1212

13-
因此任意 2 个不 Compatible 的 History(T), read() 总是选择其中一个而抛弃另一个.
14-
这表示, read()函数为 **任意 2 个 History(T), 定义了一个大小关系**, 即 History(T) 的 Order:
13+
因此任意 2 个不 Compatible 的 MonoHistory, read() 总是选择其中一个而抛弃另一个.
14+
这表示, read()函数为 **任意 2 个 MonoHistory, 定义了一个大小关系**, 即 MonoHistory 的 Order:
1515

16-
- 不 Compatible 的 2 个 History(T)必须可以比较大小;
16+
- 不 Compatible 的 2 个 MonoHistory必须可以比较大小;
1717
- 无环(否则无法保证 read 选择的确定性: 不同的比较顺序会得出不同的结果).
1818

19-
## History(T) Order
19+
## MonoHistory Order
2020

21-
对于 History(T) Order,需要满足以下性质:
22-
给定 `h1: History(t1)``h2: History(t2)`,若 `t1 < t2`,则 `h1 < h2`
21+
对于 MonoHistory Order,需要满足以下性质:
22+
给定 `h1: MonoHistory(t1)``h2: MonoHistory(t2)`,若 `t1 < t2`,则 `h1 < h2`
2323

24-
这个性质确保了 History 可以增长, 即我们常说的一个公式算法的(liveness) - client 可以通过使用更大的时间 T 构造更大的 History(T) 来完成写入。
25-
这样后续的读请求就能读取并选择这个新写入的 History(T)。如果 client 无法构造更大的 History(T),
24+
这个性质确保了 History 可以增长, 即我们常说的一个公式算法的(liveness) - client 可以通过使用更大的时间 T 构造更大的 MonoHistory 来完成写入。
25+
这样后续的读请求就能读取并选择这个新写入的 MonoHistory。如果 client 无法构造更大的 MonoHistory,
2626
其写入将无法完成 Commit,造成整个系统无法向前推进。
2727

28-
值得注意的是,History 的比较关系**不要求满足传递性**。例如对于下面三个 History(T) `h1`,`h2`,`h3`,
28+
值得注意的是,History 的比较关系**不要求满足传递性**。例如对于下面三个 MonoHistory `h1`,`h2`,`h3`,
2929
假设时间 `a,b,c` 之间没有大小关系,那么:
3030
- 不 Compatible 的是: `h1 ≭ h2`, `h2 ≭ h3`
3131
- Compatible 的是: `h1 ≍ h3`
@@ -37,21 +37,21 @@ h2: a -> b
3737
h3: x ------> b -> c
3838
```
3939

40-
当 read() 读取到这三个 History(T) 时,会选择 `h1``h3` 的并集作为返回值:
40+
当 read() 读取到这三个 MonoHistory 时,会选择 `h1``h3` 的并集作为返回值:
4141
```
4242
x -> a
4343
`-> b -> c
4444
```
4545

46-
> 实践中,大多数 History(T) Order 都满足传递性,构成偏序关系,更常见的是全序关系。
46+
> 实践中,大多数 MonoHistory Order 都满足传递性,构成偏序关系,更常见的是全序关系。
4747
>
48-
> 以下是一些具体系统中 read 操作选择 History(T) 的例子:
48+
> 以下是一些具体系统中 read 操作选择 MonoHistory 的例子:
4949
>
50-
> - Paxos: 仅允许提交单个值,其 History(T) 形式为 `(value_ballot_num, value)`,通过 `value_ballot_num`
50+
> - Paxos: 仅允许提交单个值,其 MonoHistory 形式为 `(value_ballot_num, value)`,通过 `value_ballot_num`
5151
> 比较大小。在 Phase-1 中,Proposer 遇到多个现有值时,选择最大 `value_ballot_num` 对应的值。
5252
>
53-
> - Raft: History(T) 是一组 log,大小关系由最大 log id `(last_log_term, last_log_index)` 决定。
53+
> - Raft: MonoHistory 是一组 log,大小关系由最大 log id `(last_log_term, last_log_index)` 决定。
5454
> 这体现在 election 过程中,具有最大 last_log_id 的 candidate 才能当选。
5555
>
56-
> 本文讨论的 History(T) 是一个抽象概念,仅需满足:
57-
> 是 DAG 结构,且 Order 中可比较的关系由 History(T) 中的最大时间 T 决定。
56+
> 本文讨论的 MonoHistory 是一个抽象概念,仅需满足:
57+
> 是 DAG 结构,且 Order 中可比较的关系由 MonoHistory 中的最大时间 T 决定。

src/list/raxos/def-universe-read.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# 线性宇宙中的read
22

3-
虽然不知道History(T) 的Order是什么, 但可以先假定它已经存在了,
4-
那么现在分布式共识中, read() 就要负责从多重宇宙中选择一个或几个互相兼容的History(T) 返回给调用者.
3+
虽然不知道MonoHistory 的Order是什么, 但可以先假定它已经存在了,
4+
那么现在分布式共识中, read() 就要负责从多重宇宙中选择一个或几个互相兼容的MonoHistory 返回给调用者.
55

6-
read() 选择History(T) 的算法描述:
6+
read() 选择MonoHistory 的算法描述:
77

8-
- 在History(T)的初始集合S中, 找出最大的, 即那些不小于任何其他History(T)的History(T).
9-
这些History(T) 需要保留的, 放入 "已选择" 的集合中, 同时从S中移除与其不Compatible的所有History(T).
8+
- 在MonoHistory的初始集合S中, 找出最大的, 即那些不小于任何其他MonoHistory的MonoHistory.
9+
这些MonoHistory 需要保留的, 放入 "已选择" 的集合中, 同时从S中移除与其不Compatible的所有MonoHistory.
1010
- 重复上面的过程, 直到S为空.
1111

1212
read() 的实现:
@@ -21,7 +21,7 @@ trait Universe: Distributed {
2121
while !candidate_histories.is_empty() {
2222
for candidate in candidate_histories {
2323

24-
// 检查h1是否是最大的, 即不小于任何其他History(T)
24+
// 检查h1是否是最大的, 即不小于任何其他MonoHistory
2525
let mut is_maximal = true;
2626
for other in candidate_histories {
2727
if !candidate.is_compatible_with(other) {
@@ -39,7 +39,7 @@ trait Universe: Distributed {
3939
}
4040
}
4141
}
42-
// 合并所有兼容的History(T)
42+
// 合并所有兼容的MonoHistory
4343
History::merge_compatible(selected_histories)
4444
}
4545
}

src/list/raxos/def-write.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11

22
# Write 约束
33

4-
在多重宇宙环境中, 所有 write 到`write_quorum`History(T) 都可以被读到, 因为 read()不会舍舍弃任何结果, 但是当把多重宇宙压成单一结果时, read()就要根据 History(T)的 Order 关系舍弃到较小的不 Compatible 的 History(T), 因此简单的 write 并不能保证被读到了, 只有足够大的 History(T)在写入后才能被读到.
4+
在多重宇宙环境中, 所有 write 到`write_quorum`MonoHistory 都可以被读到, 因为 read()不会舍舍弃任何结果, 但是当把多重宇宙压成单一结果时, read()就要根据 MonoHistory的 Order 关系舍弃到较小的不 Compatible 的 MonoHistory, 因此简单的 write 并不能保证被读到了, 只有足够大的 MonoHistory在写入后才能被读到.
55

6-
但是,当 write() 一个比较大的 History(T) 时, 可能会覆盖已 commit 的其他 History(T), 导致其他写入者的写入丢失, 因此 write()之前还要保证不覆盖已经 commit 得 History(T), 具体做法就是执行一个 read() 操作, 因为 read() 保证能读到已经 committed 的 History(T): `h`, 写入者在`h`的基础上增加新的时间点 T 和 Event, 再写回到一个`write_quorum`, 就可以保证是基于最新看到的 History(T)进行写入的.
6+
但是,当 write() 一个比较大的 MonoHistory 时, 可能会覆盖已 commit 的其他 MonoHistory, 导致其他写入者的写入丢失, 因此 write()之前还要保证不覆盖已经 commit 得 MonoHistory, 具体做法就是执行一个 read() 操作, 因为 read() 保证能读到已经 committed 的 MonoHistory: `h`, 写入者在`h`的基础上增加新的时间点 T 和 Event, 再写回到一个`write_quorum`, 就可以保证是基于最新看到的 MonoHistory进行写入的.
77

8-
但是这个过程并不是原子的, 读到 committed History(T)后, 可能有其他新的`h'` 又写入了, 我们要写入的 h1 可能还会覆盖已有 committed 的值.
8+
但是这个过程并不是原子的, 读到 committed MonoHistory后, 可能有其他新的`h'` 又写入了, 我们要写入的 h1 可能还会覆盖已有 committed 的值.
99

1010
所有这里要引入一个两阶段的写, 类似于 2-phase-commit, 但是我们的算法是一个活锁, 以下是 write 完整的过程, 包括最初的 read(), 一共需要 3 次 RPC:
1111

1212
- 写入者进行一次 read()得到 committed h0;
1313
- 写入者基于 h0 增加 Event 得到 h1;
1414
- 写入者向一个`write_quorum`发一个`pre_write(h1)`,它告诉每个收到`pre_write`的节点, 下一个要写的内容, 节点则:
1515
- 对比 h1 和自己本地存储的已接受的 History 和 pre_write 的 History:
16-
- 如果 h1 小于任何一个 incompatible 的 History(T), 则返回 pre_write 失败;
17-
- 否则节点删除本地所有 h1-incompatible 的 History(T), 将 h1 添加到本地的 pre_write History 中, 返回 pre_write 成功.
16+
- 如果 h1 小于任何一个 incompatible 的 MonoHistory, 则返回 pre_write 失败;
17+
- 否则节点删除本地所有 h1-incompatible 的 MonoHistory, 将 h1 添加到本地的 pre_write History 中, 返回 pre_write 成功.
1818
这一步的目的是阻止系统中任何`h: h < h1` 都不可以 commit, 保证`h1`的写入不会意外覆盖已 committed 的值.
1919
- 写入者向一个`write_quorum`发一个 `write(h1)` , 收到的节点则:
2020
- 检查本地已接收的 History 或 pre_write 的 History, 是否包含 h: h ≭ h1 且 h > h1, 如果有, 说明有其他写入者在阻止这次写入, 返回写入失败.
@@ -23,7 +23,7 @@
2323
至此, 单宇宙的共识就描述完了, 下面是一个完整的执行 write 的例子,这个例子中使用一个简单的有4个vertex的时间系统:
2424

2525
- 初始状态: 1->3 完成了 prepare, 但是 write 只写到 N2,未完成 commit;
26-
- step-0: read(N1,N3): 得到一个 History(T), `1`, 它可能是已经 committed, 在此基础上, 添加要写入的 Event 在 T=4;
26+
- step-0: read(N1,N3): 得到一个 MonoHistory, `1`, 它可能是已经 committed, 在此基础上, 添加要写入的 Event 在 T=4;
2727
- step-1: prepare_write(N1,N3), 都成功,其中 N3 节点上删掉了 Incompatible 的 prepared History: 1->3;
2828
- step-2: write(N2,N3): 都成功, 其中 N2 节点上删除了 Incompatible 的 1->3; 写入完成 commit.
2929

0 commit comments

Comments
 (0)