基于源码学习PostgreSQL-Storage
官方参考文档:https://www.postgresql.org/docs/16/storage.html
Database Page Layout
Page的具体结构在参考文档和bufpage.h
中均有说明,下面从PageInit
函数开始学习。
PageInit
在向Page插入数据前,必须调用PageInit
来初始化页面。
调试步骤
- gdb打断点:
b PageInit
- 控制台执行命令:
create table tb(id int,name varchar);
- 断点触发,查看堆栈:创建与表
tb
关联的toast表pg_toast_22952
(后面章节再说明),并且把该表的列属性插入系统目录表pg_attribute
。tb
和pg_toast_22952
的oid
分别是22952
和22955
,使用select * from pg_class where oid=22952 or oid=22955
可以查询到tb
和pg_toast_22952
。#0 PageInit (page=0x70505ef93000 "", pageSize=8192, specialSize=0) at bufpage.c:44 #1 0x00005a3e7404ded5 in RelationAddBlocks (relation=0x70506a8e06a8, bistate=0x0, num_pages=1, use_fsm=true, did_unlock=0x7ffd4d7e046d) at hio.c:364 #2 0x00005a3e7404e71b in RelationGetBufferForTuple (relation=0x70506a8e06a8, len=144, otherBuffer=0, options=0, bistate=0x0, vmbuffer=0x7ffd4d7e050c, vmbuffer_other=0x0, num_pages=1) at hio.c:768 #3 0x00005a3e74033c1b in heap_multi_insert (relation=0x70506a8e06a8, slots=0x5a3e7631dfb8, ntuples=6, cid=1, options=0, bistate=0x0) at heapam.c:2215 #4 0x00005a3e74114a68 in CatalogTuplesMultiInsertWithInfo (heapRel=0x70506a8e06a8, slot=0x5a3e7631dfb8, ntuples=6, indstate=0x5a3e763c92b8) at indexing.c:280 #5 0x00005a3e741070ff in InsertPgAttributeTuples (pg_attribute_rel=0x70506a8e06a8, tupdesc=0x5a3e763bda88, new_rel_oid=22955, attoptions=0x0, indstate=0x5a3e763c92b8) at heap.c:784 #6 0x00005a3e741073a7 in AddNewAttributeTuples (new_rel_oid=22955, tupdesc=0x70506a394fb8, relkind=116 't') at heap.c:859 #7 0x00005a3e7410826a in heap_create_with_catalog (relname=0x7ffd4d7e2950 "pg_toast_22952", relnamespace=99, reltablespace=0, relid=22955, reltypeid=0, reloftypeid=0, ownerid=10, accessmtd=2, tupdesc=0x5a3e76321348, cooked_constraints=0x0, relkind=116 't', relpersistence=112 'p', shared_relation=false, mapped_relation=false, oncommit=ONCOMMIT_NOOP, reloptions=0, use_user_acl=false, allow_system_table_mods=true, is_internal=true, relrewrite=0, typaddress=0x0) at heap.c:1414 #8 0x00005a3e741477cf in create_toast_table (rel=0x70506a390878, toastOid=0, toastIndexOid=0, reloptions=0, lockmode=8, check=false, OIDOldToast=0) at toasting.c:251 #9 0x00005a3e741472b7 in CheckAndCreateToastTable (relOid=22952, reloptions=0, lockmode=8, check=false, OIDOldToast=0) at toasting.c:90 #10 0x00005a3e74147250 in NewRelationCreateToastTable (relOid=22952, reloptions=0) at toasting.c:77 #11 0x00005a3e7457e12f in ProcessUtilitySlow (pstate=0x5a3e7631dd48, pstmt=0x5a3e762f47a8, queryString=0x5a3e762f38e8 "create table tb(id int,name varchar);", context=PROCESS_UTILITY_TOPLEVEL, params=0x0, queryEnv=0x0, dest=0x5a3e762f4a68, qc=0x7ffd4d7e3250) at utility.c:1203
- gdb:
c
;断点再次触发:创建索引pg_toast_22952_index
上面第3步的堆栈中heap_multi_insert -> RelationGetBufferForTuple -> RelationAddBlocks -> PageInit
说明了在向堆表插入数据时,首先会寻找插入数据的页面,没有页面或页面空间不足时会调用增加并初始化页面。
heapam_handler.c
文件中的heapam_methods
是堆表的访问方法集合。下面从heapam_tuple_insert
函数入手学习数据插入堆表的过程。