Hugo ʕ•ᴥ•ʔ Bear Blog

基于源码学习PostgreSQL-Storage

官方参考文档:https://www.postgresql.org/docs/16/storage.html

源码版本:github仓库的REL_16_STABLE分支

Database Page Layout

Page的具体结构在参考文档和bufpage.h中均有说明,下面从PageInit函数开始学习。

PageInit

在向Page插入数据前,必须调用PageInit来初始化页面。

调试步骤

  1. gdb打断点:b PageInit
  2. 控制台执行命令:create table tb(id int,name varchar);
  3. 断点触发,查看堆栈:创建与表tb关联的toast表pg_toast_22952(后面章节再说明),并且把该表的列属性插入系统目录表pg_attributetbpg_toast_22952oid分别是2295222955,使用select * from pg_class where oid=22952 or oid=22955可以查询到tbpg_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
    
  4. gdb:c;断点再次触发:创建索引pg_toast_22952_index

上面第3步的堆栈中heap_multi_insert -> RelationGetBufferForTuple -> RelationAddBlocks -> PageInit说明了在向堆表插入数据时,首先会寻找插入数据的页面,没有页面或页面空间不足时会调用增加并初始化页面。

heapam_handler.c文件中的heapam_methods是堆表的访问方法集合。下面从heapam_tuple_insert函数入手学习数据插入堆表的过程。

#Database #Postgresql