第 13 課 PostgreSQL 存儲(chǔ)之Page(頁面)源碼分析

在文章:PostgreSQL 數(shù)據(jù)存儲(chǔ)結(jié)構(gòu) 中我們介紹了控制頁和數(shù)據(jù)頁的基本存儲(chǔ)結(jié)構(gòu)卓舵,那是從物理上進(jìn)行說明各種頁面的用途开睡。

下面我們是從代碼邏輯上來分析頁面是如何進(jìn)行操作和控制的萨赁。

頁面布局示意圖

image.png

PageHeader

先簡單的看一下源代碼中定義的Page頭部信息結(jié)構(gòu)體寻馏,中文是我自己的理解:
源碼位置:/src/include/storage/bufpage.h

typedef struct PageHeaderData
{
    /* XXX LSN is member of *any* block, not only page-organized ones */
    /* 
       日志文件信息,保存了該頁面最后一次被修改的操作對(duì)應(yīng)到確切的日志文件
       位置壁熄,包括了日志文件ID和日志文件偏移量
    */
    XLogRecPtr  pd_lsn;         /* LSN: next byte after last byte of xlog
                                 * record for last change to this page */
    uint16      pd_tli;         /* least significant bits of the TimeLineID
                                 * containing the LSN */
    /* 用來表示頁面狀態(tài) */
    uint16      pd_flags;       /* flag bits, see below */
    /* 空閑空間起始位置 */
    LocationIndex pd_lower;     /* offset to start of free space */
    /* 空閑空間結(jié)束位置 */
    LocationIndex pd_upper;     /* offset to end of free space */
    /* 特殊用途空間的起始位置帚豪,結(jié)束位置是page尾部,直到頁面結(jié)束 */
    LocationIndex pd_special;   /* offset to start of special space */
    uint16      pd_pagesize_version;
    /* 頁面類型: 有多種控制頁面類型和數(shù)據(jù)頁面 */
    uint8       pd_type;
    /* 物理存儲(chǔ)與邏輯存儲(chǔ)的關(guān)聯(lián)對(duì)象的OID */
    Oid         pd_oid;         /* oid of related object,
                                 * pg_class.oid for IAM, pg_class.relfilenode for others */
    /* 數(shù)據(jù)開始位置 */
    ItemIdData  pd_linp[1];     /* beginning of line pointer array */
} PageHeaderData;

header用來保存該page相關(guān)的數(shù)據(jù)草丧。

  • pd_lsn狸臣、pd_tli 記錄日志相關(guān)的信息。

  • pd_flags 表示頁面狀態(tài)
    PD_ALL_VISIBLE(0x0001) - 表示所有元組可以訪問昌执。
    PD_VALID_FLAG_BITS(0x0003) - 加密存儲(chǔ)相關(guān)烛亦。
    PG_PAGE_ENCRYPTED(0x0002) - 支持統(tǒng)一存儲(chǔ)加密引擎。

  • pd_lower
    空閑空間起始位置懂拾,隨著插入和刪除操作位置發(fā)生變化煤禽。初始化時(shí)就是pd_linp的偏移位置。

  • pd_upper
    空閑空間結(jié)束位置岖赋,隨著插入和刪除操作位置發(fā)生變化檬果。初始化時(shí)與pd_special相同。

  • pd_special
    相當(dāng)于畫了一條線唐断,從pd_special這個(gè)位置到page的結(jié)尾选脊,都是special的地盤,普通插入Tuple脸甘,都不許進(jìn)入這個(gè)私有地盤恳啥。而且這個(gè)pd_special一旦初始化之后,這個(gè)值就不會(huì)動(dòng)了斤程。
    主要用于加密存儲(chǔ)是保存加密相關(guān)的數(shù)據(jù)角寸。

  • pd_pagesize_version
    高位字節(jié)表示page大小。
    低位字節(jié)表示版本號(hào)(PG_PAGE_LAYOUT_VERSION)忿墅,代碼寫死扁藕。
    宏P(guān)ageSetPageSizeAndVersion用于設(shè)置大小和版本。
    宏P(guān)ageGetPageSize()獲取Page大小疚脐。
    宏P(guān)ageGetPageLayoutVersion()獲取版本號(hào)亿柑。
    對(duì)應(yīng)的實(shí)現(xiàn):

#define PageSetPageSizeAndVersion(page, size, version) \
( \
    AssertMacro(((size) & 0xFF00) == (size)), \
    AssertMacro(((version) & 0x00FF) == (version)), \
    ((PageHeader) (page))->pd_pagesize_version = (size) | (version) \
)
#define PageGetPageSize(page) \
    ((Size) (((PageHeader) (page))->pd_pagesize_version & (uint16) 0xFF00))
#define PageGetPageLayoutVersion(page) \
    (((PageHeader) (page))->pd_pagesize_version & 0x00FF)
  • pd_type
    有這些類型:P_GAM、P_IAM棍弄、P_PFS望薄、P_DCM疟游、P_BCM、P_SGAM痕支、P_VM颁虐。
    對(duì)應(yīng)的定義:
typedef enum PageType{
    P_TEMPDATA,
    P_HEAP,
    P_BTREE,
    P_HASH,
    P_GIN,
    P_GIST,
    P_SEQUENCE,
    P_GAM,
    P_PFS,
    P_SGAM,
    P_BCM,
    P_DCM,
    P_IAM,
    P_VM, /* vm page*/
    P_UNKNOWN,
}PageType;

Page初始化

通過如下函數(shù)初始化頁面:

void
PageInit(Page page, Size pageSize, Size specialSize, PageType type)
{
    PageHeader  p = (PageHeader) page;
    uint16      pd_flags = p->pd_flags;

    specialSize = MAXALIGN_DISK(specialSize);

    Assert(pageSize == BLCKSZ);
    Assert(pageSize > specialSize + SizeOfPageHeaderData);

    /* Make sure all fields of page are zero, as well as unused space */
    MemSet(p, 0, pageSize);

    /* p->pd_flags = 0;                     done by above MemSet */
    PageSetPageSizeAndVersion(page, pageSize, PG_PAGE_LAYOUT_VERSION);
    PageSetPageType(page, type);
    PageSetOid(page, InvalidOid); /* we will set it later for heap page */
    /* Support the uniform store encryption engine. */
    p->pd_lower = SizeOfPageHeaderData;
    if ((pd_flags & PG_PAGE_ENCRYPTED) && !PageIsCtrlPage(page))
        p->pd_special = pageSize - specialSize -
                        G_EncryptData->block_key_num * (G_EncryptData->key_len + G_EncryptData->verify_len);
    else
        p->pd_special = pageSize - specialSize;
    p->pd_upper = p->pd_special;

    /*
     * Empty page is all visible. We must set PD_ALL_VISIBLE because 
     * recycled page's "visibility map bit" may be set before. (Recycled page -- 
     * means page was deallocated by Vacuum or something else, and then 
     * be allocated.)
     */
    PageSetAllVisible(p);
    if ((pd_flags & PG_PAGE_ENCRYPTED) && !PageIsCtrlPage(page))
        PageSetEncrypted(p);
}

待分析...

Page有效性檢查

通過如下函數(shù)實(shí)現(xiàn):

bool
PageHeaderIsValid(PageHeader page)
{
    char       *pagebytes;
    int         i;

    /* Check normal case */
    /* Support the uniform store encryption engine. */
    if (PageGetPageSize(page) == BLCKSZ &&
        PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION &&
        (page->pd_flags & ~PD_VALID_FLAG_BITS) == 0 &&
        page->pd_lower >= SizeOfPageHeaderData &&
        page->pd_lower <= page->pd_upper &&
        page->pd_upper <= page->pd_special &&
        (PageIsEncrypted(page) ?
            page->pd_special <= BLCKSZ - G_EncryptData->block_key_num * (G_EncryptData->key_len + G_EncryptData->verify_len) :
            page->pd_special <= BLCKSZ) &&
        page->pd_special == MAXALIGN_DISK(page->pd_special))
        return true;

    /* Check all-zeroes case */
    pagebytes = (char *) page;
    for (i = 0; i < BLCKSZ; i++)
    {
        /* Support the uniform store encryption engine. */
        if (pagebytes[i] != 0 && pagebytes[i] != 2)
            return false;
    }
    
    return true;
}

待分析...

Insert操作分析

當(dāng)初始化的時(shí)候,pd_lower設(shè)置為SizeOfPageHeaderData卧须,pd_upper設(shè)置為和pd_special一樣另绩。但是注意,這個(gè)lower和upper不是固定的花嘶,隨著Tuple的不斷插入笋籽,lower變大,而upper不斷變小椭员。當(dāng)我們每插入一條Tuple车海,需要在當(dāng)前的lower位置再分配一個(gè)Item,記錄Tuple的長度隘击,Tuple的起始位置offset侍芝,還有flag信息。這個(gè)Page Header中的pd_lower就是記錄分配下一個(gè)Item的起始位置闸度。所以如果不斷插入竭贩,lower不斷增加,每增加一條Tuple莺禁,就要分配一個(gè)Item(4個(gè)字節(jié))

對(duì)應(yīng)實(shí)現(xiàn)函數(shù):

  • PageAddItem
OffsetNumber
PageAddItem(Page page,
            Item item,
            Size size,
            OffsetNumber offsetNumber,
            Size tupleSize,
            ItemIdFlags flags)

待分析...

Delete操作分析

對(duì)應(yīng)實(shí)現(xiàn)函數(shù):

  • PageIndexMultiDelete
void
PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)

offnum指示第幾個(gè)記錄留量,offnum是從1開始計(jì)數(shù)的,查找對(duì)應(yīng)item 是offnum-1.
我們找到Item哟冬,就可以找到Tuple對(duì)應(yīng)的offset和size楼熄。
待分析...

發(fā)現(xiàn)更多寶藏

我在喜馬拉雅上分享聲音

《PostgreSQL數(shù)據(jù)庫內(nèi)核分析》,點(diǎn)開鏈接可以聽聽浩峡,有點(diǎn)意思可岂。

《數(shù)據(jù)庫系統(tǒng)概論(第4版)》,點(diǎn)開鏈接可以聽聽翰灾,有點(diǎn)意思缕粹。

更多IT有聲課程,點(diǎn)我發(fā)現(xiàn)更多

第 0 課 PostgreSQL 系列文章列表

其他相關(guān)文章分享列表:

第 23 課 PostgreSQL 創(chuàng)建自己的數(shù)據(jù)庫纸淮、模式平斩、用戶
第 22 課 PostgreSQL 控制文件
第 21 課 PostgreSQL 日志系統(tǒng)
第 16 課 查詢過程源碼分析
第 15 課 PostgreSQL 系統(tǒng)參數(shù)配置
第 14 課 PostgreSQL 數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)
第 13 課 PostgreSQL 存儲(chǔ)之Page(頁面)源碼分析
第 12 課 PostgreSQL 認(rèn)證方式
第 11 課 PostgreSQL 增加一個(gè)內(nèi)核C函數(shù)
第 10 課 PostgreSQL 在內(nèi)核增加一個(gè)配置參數(shù)
第 09 課 PostgreSQL 4種進(jìn)程啟動(dòng)方式
第 08 課 PostgreSQL 事務(wù)介紹
第 07 課 PostgreSQL 數(shù)據(jù)庫、模式咽块、表绘面、空間、用戶間的關(guān)系
第 06 課 PostgreSQL 系統(tǒng)表介紹
第 05 課 PostgreSQL 編譯源代碼進(jìn)行開發(fā)
第 04 課 PostgreSQL 安裝最新的版本
第 03 課 PostgreSQL 代碼結(jié)構(gòu)
第 02 課 PostgreSQL 的特性、應(yīng)用揭璃、安裝
第 01 課 PostgreSQL 簡介及發(fā)展歷程

上面文章都在專輯中:PostgreSQL專輯鏈接晚凿,點(diǎn)我查看

如果有用,可以收藏這篇文件瘦馍,隨時(shí)在更新....

更多交流加群: PostgreSQL內(nèi)核開發(fā)群 876673220

親歼秽,記得點(diǎn)贊、留言情组、打賞額U芤!呻惕!

上一課
下一課

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市滥比,隨后出現(xiàn)的幾起案子亚脆,更是在濱河造成了極大的恐慌,老刑警劉巖盲泛,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件濒持,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡寺滚,警方通過查閱死者的電腦和手機(jī)柑营,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來村视,“玉大人官套,你說我怎么就攤上這事∫峡祝” “怎么了奶赔?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長杠氢。 經(jīng)常有香客問我站刑,道長,這世上最難降的妖魔是什么鼻百? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任绞旅,我火速辦了婚禮,結(jié)果婚禮上温艇,老公的妹妹穿的比我還像新娘因悲。我一直安慰自己,他們只是感情好中贝,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布囤捻。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝎土。 梳的紋絲不亂的頭發(fā)上视哑,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音誊涯,去河邊找鬼挡毅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛暴构,可吹牛的內(nèi)容都是我干的跪呈。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼取逾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼耗绿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起砾隅,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤误阻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后晴埂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體究反,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年儒洛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了精耐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡琅锻,死狀恐怖卦停,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浅浮,我是刑警寧澤沫浆,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站滚秩,受9級(jí)特大地震影響专执,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜郁油,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一本股、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧桐腌,春花似錦拄显、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春承边,著一層夾襖步出監(jiān)牢的瞬間遭殉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國打工博助, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留险污,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓富岳,卻偏偏與公主長得像蛔糯,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窖式,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 本文簡單介紹了PG數(shù)據(jù)頁P(yáng)age中存儲(chǔ)的原始內(nèi)容以及如何閱讀它們蚁飒,包括頁頭PageHeader和行數(shù)據(jù)指針I(yè)tem...
    EthanHe閱讀 2,033評(píng)論 4 2
  • 本文簡單介紹了PG數(shù)據(jù)表的存儲(chǔ)基礎(chǔ)知識(shí)以及可用于解析數(shù)據(jù)頁P(yáng)age內(nèi)容的pageinspcet插件。 一萝喘、PG數(shù)...
    EthanHe閱讀 5,077評(píng)論 4 4
  • 前情回顧 三 更 我跟海哥住在一起飒箭,我們住的是省重點(diǎn)高中旁的學(xué)區(qū)別墅,海哥可不差錢蜒灰。想一想,盜戰(zhàn)國墓肩碟,什么青銅六山...
    瑩Innsane閱讀 283評(píng)論 1 1
  • 三月份那時(shí)在找工作强窖,無意間搜公眾號(hào)看文章,看了一篇何沐芝老師的文章削祈,現(xiàn)在記不得是哪一篇文章了翅溺,進(jìn)而加了微信,令我意...
    廖阿凡閱讀 178評(píng)論 0 2
  • 昨晚南科大實(shí)驗(yàn)二小的劉安老師給大家分享了信息技術(shù)提升班第四課《網(wǎng)絡(luò)技能及學(xué)習(xí)軟件》髓抑。劉老師從下面幾個(gè)方面為...
    寧都謝志雄閱讀 884評(píng)論 7 11