TableAmRoutine
src/include/access/tableam.h
TableAmRoutine是表访问方法的API结构体,作为服务端声明周期有效的数据结构,需要将其作为静态常量结构体定义,通过FormData_pg_am.amhandler获取。如果需要实现其他TableAM,只需要实现自己的TableAmRoutine结构,实现并定义TableAmRoutine里面所有的API。
- 为新的表访问方式创建TableAmRoutine表访问方法的API结构体
- 实现新访问方式TableAmRoutine的API结构体中的方法
- 创建GetXXXamTableAMRoutine和XXX_tableam_handler函数用于获取TableAmRoutine表访问方法的API结构体
- 向fmgr中注册相应TableAmRoutine结构体,用于通过amhandler的Oid查询相应的TableAmRoutine结构体(PostgreSQL数据库TableAM——GetTableAmRoutine函数)
TableAmRoutine接口使用
以PostgreSQL数据库TableAM——HeapAM为例,如下为其TableAmRoutine的slot_callbacks成员的值。
顺序扫描相关接口
.scan_begin = heap_beginscan
.scan_end = heap_endscan
.scan_rescan = heap_rescan
.scan_getnextslot = heap_getnextslot
.parallelscan_estimate = table_block_parallelscan_estimate
.parallelscan_initialize = table_block_parallelscan_initialize
.parallelscan_reinitialize = table_block_parallelscan_reinitialize
索引扫描相关接口
.index_fetch_begin = heapam_index_fetch_begin
.index_fetch_reset = heapam_index_fetch_reset
.index_fetch_end = heapam_index_fetch_end
.index_fetch_tuple = heapam_index_fetch_tuple
.scan_bitmap_next_block = heapam_scan_bitmap_next_block
.scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple
DML/DDL相关接口
.tuple_insert = heapam_tuple_insert
.multi_insert = heapam_multi_insert
.tuple_delete = heapam_tuple_delete
.tuple_update = heapam_tuple_update
.relation_vacuum = heap_vacuum_rel
统计相关接口
.scan_analyze_next_block = heapam_scan_analyze_next_block
.scan_analyze_next_tuple = heapam_scan_analyze_next_tuple
.relation_size = table_block_relation_size
.relation_estimate_size = heapam_estimate_rel_size
TTSOpsHeapTuple是最重要的一个接口,TupleTableSlot结构是执行器操作和传输的结构,执行器只关心逻辑上的行定义,即行由几列组成,每列的值存放在slot->values[]数组中,执行器不关心底层的tuple是怎么存储的,所以Access Method需要自己定义函数对底层物理存储进行转换,将其转换执行器想得到的数据。例如,只想你过去想得到第n列的值,它会调用getsomeattrs接口,实际上调用的是Heap的tts_heap_getsomeattrs。
TableAm相关Generic routine
src/backend/access/table/tableamapi.c包含如下函数
GetTableAmRoutine函数调用指定access method handler routine以获取其TableAmRoutine结构体,该结构体会在调用者的内存上下文中分配。主要是通过调用OidFunctionCall0(amhandler)函数获取TableAmRoutine结构体。
将宏展开OidFunctionCall0(amhandler)
就是OidFunctionCall0Coll(amhandler, InvalidOid)
,OidFunctionCall0Coll函数详情如下:
check_default_table_access_method函数用于校验新的default_table_access_method是否合法。
src/include/access/tableam.h包含如下函数,主要逻辑就是通过Relation的rd_tableam(TableAmRoutine结构体)调用相应AM的成员函数。
table相关Generic routine(打开关闭table)
src/backend/access/table/table.c 主要是通过调用relation.c中函数获取RelationData结构体,PostgreSQL数据库RelationAM——relation related routines。
table_open函数通过relation OID打开表relation,函数检查relation不是索引或复合类型,调用者需要检查relation不是一个视图或外部表。table_open函数直接调用relation_open函数。
table_openrv函数打开由RangeVar节点指定的表relation
table_openrv_extended函数打开由RangeVar节点指定的表relation,但是可以通过missing_ok标志来指定在relation-not-found时返回NULL而不是直接失败。
table_close关闭table
table相关AM routine(操作table)
src/backend/access/table/tableam.c
Table AM当前的一些限制:
- AMs期望是基于块组织的,代码中有很多这样的假设,像统计信息,analyzes取样都是基于块的
- redo类型被PG内核支持,而新的WAL类型例如redo类型不在核心代码中,所以很难在AM中使用新的WAL类型,必须改动核心代码
- AMs和planner和执行器需要更好的集成和优化,例如对列存的支持,const估算需要更加精确,scan需要知道所选列的信息等
- 代码中还有很多代码是基于heap的假设,例如通过xmin来进行cache的可见性判断