如何处理Lance表并发冲突
Lance表采用MVCC(多版本并发控制)机制:每个版本由一个不可变的manifest描述,该manifest引用fragments(数据文件)、indices(索引文件)以及可选的transaction(事务)文件。读操作读取某个特定的manifest版本,因此支持快照读取;写操作通过提交新的manifest来生成新版本,从而实现ACID语义(至少在单表或单数据集的范围内)。Lance的“事务”(transaction)是一次写入、更新、删除或建索引等变更提交(commit)后,生成一个新的表版本。
Lance事务提交流程
- 基于某个基线版本(base version)构造事务,例如追加新的fragments、生成新的索引引用等(事务本质是“相对基线manifest的变更”)。
- 写入事务相关的新文件,先把新fragments/ 删除文件 / 索引等写到存储中(这些文件本身是不可变的)。
- 原子提交manifest,最后一步尝试“原子地”写出一个新的manifest文件作为新版本的入口;如果并发写导致原子提交失败,会进入冲突检测/重试/可能的rebase。
事务冲突
当两个或多个用户都基于同一个base版本提交时,就会出现冲突窗口:各方均试图将“下一版本”指向各自的新manifest。Lance会在提交阶段检测到这一点,并尝试用事务文件/冲突规则做判断与(有条件的)自动合并或rebase;否则返回提交冲突。
- Lance事务操作类型
表1 Lance事务操作类型说明 事务名称
事务描述
涉及语句(如不涉及标注为N/A)
Append
将新的分片添加到表中,不会修改现有数据。
INSERT
Delete
使用删除向量将行标记为已删除。
N/A
Overwrite
创建或完全用新数据、新schema和新配置覆盖该表。
INSERT OVERWRITE、TRUNCATE
CreateIndex
添加、替换或删除二级索引(向量索引、标量索引、全文检索索引)。
CREATE INDEX/DROP INDEX/REBUILD INDEX/OPTIMIZE INDEX
Rewrite
对数据进行重组,不改变数据的语义。包括压缩、去重、重排等操作。
N/A
Merge
向表中添加新列,从而修改表结构。必须更新所有分片以包含这些新列。
ADD COLUMN、ALTER COLUMN TYPE
Project
从表中删除列,从而修改表结构。这是一个仅涉及元数据的操作;数据文件不会被修改。
DROP COLUMN、ALTER COLUMN RENAME
Restore
将表恢复到之前的版本。
N/A
ReserveFragments
预分配分片ID,以便在将来的重写操作中使用。
N/A
Clone
创建表的浅拷贝或深拷贝。浅拷贝是仅包含元数据的拷贝,这些拷贝通过base_paths引用原始数据文件。
N/A
Update
修改行数据值,而不会添加或删除行。
UPDATE
UpdateConfig
修改表配置、表元数据、schema元数据或字段元数据,而不改变数据本身。
ALTER SET/UNSET
DataReplacement
将特定列区域的数据替换为新的数据文件。
N/A
UpdateMemWalState
更新MemWal索引(基于预写日志的索引)的状态。
N/A
UpdateBases
向表中添加新的基础路径,从而能够引用其他位置的数据文件。
N/A
- 事务冲突类型
表2 事务冲突类型说明 冲突类型
描述
当前机制
Rebasable Conflict
事务可以进行修改以适应并发更改,同时保持其语义意图。事务会进行转换以适应并发修改,然后在提交层自动重试提交。
提交层重试提交,如果重试次数消耗完毕则报错。
Retryable Conflict
事务无法进行合并,会返回一个可重试冲突错误,应用层应该重新更新数据后进行重试提交。
直接报错。
Incompatible Conflict
事务之间存在根本性冲突,重试会违反操作的假设,或产生与预期语义不同的结果。提交操作失败,并返回不可重试的错误。
直接报错。
