作者:张连壮 PostgreSQL 研发工程师
从事多年 PostgreSQL 数据库内核开发,对 citus 有非常深入的研究。
上一期 我们介绍了 PostgreSQL 数据找回工具:pg_reconvery
本文将带大家了解 pg_recovery 工具的实现原理、设计思路,并带来源码解读。
| 数据找回的实现原理
一个数据库系统正常的数据读取方式,是从做 select * from pg_recovery
的查询开始(即执行事务),执行查询操作过程将同时生成事务的快照,通过 GetActiveSnapshot()
函数,便可以看到当前可见的数据。
| 设计思路
- 如何读取 Dead 元组?
PostgreSQL 通过 快照 来决定当前数据库数据的可见性,因此当一条数据被删除时,数据的实体仍然存在于数据库实例中,通常管这种不可见的数据叫做 Dead 元组(PostgreSQL 中一条数据称为一个元组)。
PostgreSQL 中提供了 SnapshotAny 的特殊快照(还有很多其他类型)。这个快照可以读取任何数据,pg_recovery 便是通过该方式读取的所有数据。默认情况下,只返回 recovery 的数据,不返回可见的数据。
- 函数一次返回多少数据?
数据量是按行返回的,并且每次限定一行。
- 如何控制内存?
函数会多次执行,而有些状态是全局级的。因此可以使用 multi_call_memory_ctx
(内存池的上下文)参数,来控制内存。
关于函数的参数
通过 SQL 创建函数时,执行如下语句。函数使用请参照上一期内容。
1 | sql复制代码CREATE FUNCTION pg_recovery(regclass, recoveryrow bool DEFAULT true) RETURNS SETOF record |
regclass:PostgreSQL 的表类型,会将表名自动转换成 OID(OID 数据库内部对象的唯一标识),因此只需输入表名即可。
reconveryrow bool DEFAULT ture:默认值 true,表示只返回 recovery 数据。取值 false, 表示返回所有数据。
执行下列语句,修改参数默认值。
1 | csharp复制代码select * from pg_recovery('aa', recoveryrow => false) |
RETURNS SETOF record:函数返回行类型数据。
| 源码解读
必要的数据
1 | ini复制代码typedef struct |
隐藏列
增加 recoveryrow 的隐藏列,当返回全部信息时,通过此列可以辨别出该行数据是 recovery 的数据,还是用户可见的数据。
1 | objectivec复制代码static const struct system_columns_t { |
pg_recovery 简化代码
1 | ini复制代码Datum |
生成映射表
1 | ini复制代码TupleConversionMap * |
元组转换函数
1 | ini复制代码HeapTuple |
本文转载自: 掘金