4.3.2 FDW
openGauss使用FDW API与内存引擎进行对接。实现上分为两个层次。
(1) 消费者层——FDW API的实现,它由提供数据管理和操作的静态函数组成。这些函数通过fdwapi.h中的FdwRoutine结构以回调的形式暴露给上层。
(2) 通信层——连接openGauss其他部分和MOT内部API。这包括数据和数据定义转换和对MOT内部表示的调整。
- 消费者层
MOT消费者层FDW API的功能和用途如表4-35所示。其中,计划、执行阶段请参考《SELECT/UPDATE/DELETE(计划阶段)》以及《SELECT/UPDATE/DELETE(执行阶段)》两小节。
- 主要流程时序图
请注意,为了便于读者更好的理解正常流程和异常流程的关系,本节中的时序图均将正常流程和异常流程放在同一张图中,其中P1、P2……Pn为异常流程。同时,为简化时序图帮助理解流程,异常流程仅在异常发生的位置进行标识,未完整绘制异常流程的时序。
1) CREATE表
用户创建一个新的内存表时,openGauss通过FDW适配器将请求转发给MOT存储引擎。创建表的正常流程和主要异常流程如图4-44所示。
正常事件流:FDW创建一个新的表对象。然后对每个列执行以下操作。
(1) FDW验证列定义。
(2) MOT引擎进一步验证列定义。
(3) 创建给定类型的列对象并将其添加到表中。
(4) 对所有列定义重复此过程。
添加完所有列后表定义本身就被验证,表对象已添加到MOT引擎,并通过锁保护,最后,由于表还没有索引,所以会向表中添加一个伪主索引/键。DDL命令会持久化到重做日志中。
P1:在此异常事件流中,列定义失败时FDW通过ereport函数向openGauss报告无效列定义(invalid column definition)错误。
P2:在此异常事件流中,由于以下原因之一,导致表的列定义验证失败:①不支持的列类型;②字段大小无效;③资源限制:已超过允许的表最大列数;④资源限制:列的总大小已超过最大元组大小;⑤资源限制:列名大小超过允许的最大值。
P3:在此异常事件流中,由于以下原因之一,导致表的列定义验证失败:①资源限制:超出每个表的最大列数;②资源限制:列的总大小超过最大元组大小;③资源限制:列名大小超过允许的最大值。
P4:总元组大小超过了允许的最大元组大小。
2) DELETE表
如图4-45所示,用户DELETE内存表时,openGauss通过FDW适配器将请求转发给MOT存储引擎。
正常事件流:FDW从MOT引擎中检索表对象,并将DELETE表的请求转发给MOT引擎。DDL命令在重做日志中持久化,然后对于表中的每个索引,索引数据将被截断并DELETE索引对象。随后对表中的每个索引重复此过程。在DELETE所有索引对象之后,MOT将DELETE表对象并返回给FDW。
P1:在此异常事件流中,没有找到索引所属的表。此错误条件被静默忽略,FDW不会向openGauss报告错误。
P2:在此异常事件流中,在表对象中找不到请求的二级索引。此错误条件被静默忽略,FDW不会向openGauss报告错误。
3) CREATE索引
如图4-46所示,用户希望在现有的内存表中创建新索引时,openGauss通过FDW适配器将请求转发给MOT存储引擎。
正常事件流:FDW从MOT引擎中检索表对象并创建一个索引对象。然后,对每个列执行以下操作:①FDW验证列大小;②FDW验证列类型。对所有列定义重复此过程。验证所有列之后,生成的键大小也会被验证。在创建主索引时,原创建表阶段时添加的伪主索引将被新的主索引替换,应当在表仍然为空时完成。否则,将向表添加二级索引。索引数据本身是由主索引数据创建的。最后,整个DDL命令将持久化到重做日志。
P1:在此异常事件流中,不支持索引类型,FDW通过ereport工具向openGauss报告未支持的特性(feature unsupported)错误。目前只支持BTREE索引类型。
P2:在此异常事件流中,列大小验证失败,FDW通过ereport实用程序向openGauss报告无效列定义错误。
P3:在此异常事件流中,列类型验证失败,FDW通过ereport实用程序向openGauss报告未支持的特性(feature unsupported)错误。
P4:在此异常事件流中,索引的总键大小超过了最大允许的键大小,FDW通过ereport工具向openGauss报告无效列定义错误。
P5:在此异常事件流中,由于资源限制(内存不足),无法执行操作。
P6:在此异常事件流中,由于以下原因之一无法执行操作:①资源限制(内存不足),无法执行操作,②唯一主键冲突。
4) DELETE索引
如图4-47所示,用户希望DELETE内存表中的现有索引时,openGauss通过FDW适配器将请求转发给MOT存储引擎。
正常事件流:FDW从MOT引擎中检索表对象,并转发从表中DELETE二级索引的请求。DDL命令在重做日志中持久化,然后截断索引数据并DELETE索引对象。
P1:在此异常事件流中,没有找到索引所属的表。此错误条件被静默忽略,FDW不会向openGauss报告错误。
P2:在此异常事件流中,在表对象中找不到请求的二级索引。此错误条件被静默忽略,FDW不会向openGauss报告错误。
5) 截断表
如图4-48所示,用户截断现有的内存表内容时,openGauss通过FDW适配器将请求转发给MOT存储引擎。
正常事件流:FDW从MOT引擎中检索表对象并转发截断表的请求。表中每个索引的索引数据被截断,并且将DDL命令持久化到重做日志。
P1:在此异常事件流中,没有找到该表。此错误条件被静默忽略,FDW不会向openGauss报告错误。
P2:在此异常事件流中,由于资源限制(内存不足),无法执行操作。
6) INSERT行
如图4-49所示,openGauss通过FDW适配器将请求转发给MOT存储引擎。可以通过自动提交(auto-commit)INSERT行,也可以在事务中INSERT行。
正常事件流:FDW从MOT引擎中检索表对象并创建新的行对象。由于内存引擎不同于磁盘引擎,不使用基于页面的间接访问形式,因此需要将行格式从openGauss行格式转换为MOT行格式(MOT将这种行格式转换称为Pack,反向转换称为unpack)后才能INSERT到表中。随后为该表的每个索引创建一个键。INSERT行的整个请求被传递到当前Txn,随后将该请求转发到并发控制模块,并持久化到重做日志。
P1:在此异常事件流中,由于资源限制(内存不足),无法执行操作。
P2:在此异常事件流中, INSERT行失败,原因如下:①内存分配失败;②在主节点上违反了唯一约束。在这两种情况下,父事务都将使用正确的错误代码中止。
7) SELECT/UPDATE/DELETE(计划阶段)
用户可以在内存表中SELECT/UPDATE/DELETE行。每个操作分为两个阶段:计划阶段和执行阶段。图4-50主要关注计划阶段。
每个SELECT/UPDATE/DELETE的规划阶段包括选择最佳执行计划。为此,openGauss准备了几个可能的执行路径,并要求FDW估计每个此类路径的开销,以便openGauss可以选择最佳的执行路径。
正常事件流:openGauss调用GetForeignRelSize接口,FDW从MOT中检索相关表对象,并用启动成本和总成本估计初始化此查询的FDW状态。openGauss调用GetForeignPaths触发所有涉及索引对象的开销计算。最后,openGauss调用GetForeignPlan触发结束整个过程,包括查询子句对本地和远程排序,以及根据所选执行路径对FDW状态进行序列化。PREPARE语句的执行在此结束,其他语句待执行的部分将在执行阶段中描述。
P1:在此异常事件流中,由于资源限制(内存不足),无法执行操作。
8) SELECT/UPDATE/DELETE(执行阶段)
如图4-51所示,计划阶段完成后,执行阶段开始。
正常事件流:openGauss调用BeginForeignScan,FDW检索相关表并初始化查询的FDW状态。在进行UPDATE/DELETE操作时,openGauss通过调用BeginForeignModify接口触发一个额外的初始化阶段,然后返回NULL。openGauss通过调用IterateForeignScan接口进行如下操作:①仅在需要时一次性初始化游标;②在当前事务对象中查找下一行;③将行数据从MOT格式转换为openGauss格式;④游标前进;⑤返回包含unpack行的槽位。重复此过程,直到游标中不再有行,并且返回NULL到openGauss。然后openGauss应用本地条件/查询子句等本地过滤器来决定是否继续处理该行。在进行SELECT操作时,该行将被添加到结果集中,并返回结果集给用户。进行UPDATE和DELETE操作需执行的其余部分将在后文中进行描述。
9)UPDATE(结束执行阶段)
执行SELECT、UPDATE和DELETE语句的公共部分后,每个语句的剩余部分有所不同。图4-52描述UPDATE的剩余部分。
正常事件流:openGauss为特定的更新元组调用ExecForeignUpdate接口。FDW更新当前事务对象中最后一行的状态以进行并发控制,然后FDW将行数据从openGauss格式转换为MOT格式,并通过覆盖该行的方式完成变更字段的更新。该操作在重做日志中持久化,并返回openGauss。
P1:在此异常事件流中,由于并发控制事务对象的行状态更新失败。在这种情况下,父事务将以适当的错误代码中止。
10) DELETE行(结束执行阶段)
图4-53描述了DELETE操作执行的剩余部分。
正常事件流:openGauss为特定更新的元组调用ExecForeignDelete接口。FDW更新当前事务对象中最后一行的状态以进行并发控制,然后将操作持久化到重做日志中,并返回openGauss。
P1:在此异常事件流中,由于并发控制事务对象的行状态更新失败。在这种情况下,父事务将以适当的错误代码中止。