在可重复读隔离级别下,对 UStore 表执行 Vacuum Full 或 Online Vacuum Full 会导致事务报错“Snapshot too old”;相同操作在 AStore 上不会触发该错误。
现象与复现
下面的测试使用两个会话。创建 test 表时,根据测试场景选择 UStore 或 AStore:
drop table dummy;
create table dummy(a int);
drop table test;
-- 以下两条语句按测试场景二选一
create table test(a int) with (storage_type=ustore);
-- create table test(a int) with (storage_type=astore);
insert into test values(1);
insert into dummy values(1);
-- Session 2:开启可重复读事务并获取快照
start transaction isolation level repeatable read;
select * from dummy;
-- Session 1:更新并执行 Online Vacuum Full
update test set a=2;
vacuum full test online;
-- Session 2:使用原快照读取 test
select * from test;
commit;
UStore 执行结果
gaussdb=# select * from dummy; -- 随便执行一条 SQL,获取快照
a
---
1
(1 row)
gaussdb=# select * from test;
ERROR: Snapshot too old, ScanRelation, the info: snapxmax is 236244314,
snapxmin is 236244311, csn is 130631, relfrozenxid64 is 236244318,
globalRecycleXid is 236244311.
gaussdb=# commit;
ROLLBACK
AStore 执行结果
gaussdb=# select * from dummy; -- 随便执行一条 SQL,获取快照
a
---
1
(1 row)
gaussdb=# select * from test;
a
---
1
(1 row)
gaussdb=# commit;
COMMIT
原因分析
UStore 将数据页面(data page)和 UNDO 日志分离存储:最新版本的数据位于数据页面,历史版本的数据位于 UNDO 空间。执行 Vacuum Full 时,系统不会复制 UNDO 日志。
相关函数: CopyUHeapDataInternal。