PostgreSQL FSM(Free Space Map) 原始碼解讀
PostgreSQL FSM(Free Space Map) 原始碼解讀
一、FSM設計目的
FSM,即空閒空間管理的設計初衷是為了能夠快速找到一個頁是否有足夠的自由空間用來容納新增的資料。如果沒有這樣的頁,則分配新頁。在PG 8.4版本以後,每個relation有自己獨立的的FSM空間(以_fsm後輟的檔案) 。
fsm檔案:
二、FSM原理
FSM總體設計上採用binary tree和High-level兩種演算法。
1. Binray tree
一個relation的每個heap page 用一個map byte表示,即8位。這也相當於將一個page的空閒空間(map value) 分為256檔位。按當前 page size 8K來算, 8K/256=32;即32位元組一個檔位。
PG只是用來粗略記錄每個頁的剩餘空間,並不會精確記錄真實有多少空間可用。
如下圖所示:
目前PG 一個relation最大支援2的32次方個page,一個page size 8K 計算,即4G*8k=32T。為了存放這麼多塊,三層樹結構,至少每個FSM page需要1626個slot。
1626*1626*1626>=2^32。
原始碼中一個relation 最大BlockNumber定義:
一個葉子節點對應一個relation heap page。分支節點代表自己所有子節點中剩餘空間的最大值。如:
假設,我們需要94個位元組,那麼可以算出map value 為:94+31/32=3.90625(演算法如下圖)。此時查詢map value為4的值,先從root節點頂層開始,一直找到底層。
請求空間時map value演算法:
以上面的樹為例,那麼分配之後的樹將變成下面的形態。即以冒泡的形式依次修改父節點branch的值。
總結:採用二叉樹後,只需要比較下root節點就可以判斷此頁剩餘空間是否滿足空間請求。
2. High-level演算法
上面的演算法假設只有一個FSM page,但是事實上,隨著表的增大,FSM 本身也會變大。FSM 樹變大後,將會超出一個page 8K的容量。所以這時就引入High-level的演算法,
解決FSM跨page的問題。從上面分析得知,一個relation最大可以有2^32次方,即4G個page。如果層數保持在3層,那麼至少每層需要1626個slot來儲存 heap page的map value值。即,1626*1626*1626>=2^32。事實上一個FSM page可以儲存 (8k-page header)/2~=4000 個 heap page的map value。那麼三層結構可以儲存 4000*4000*400>>2^32個。
所以PG用三層的High-level樹來記錄一個表是足夠的。High-level樹跟FSM low level結構相似,只是High-level的葉子節點指向FSM page (Low-level)的root節點。
PG用fsm_set_avail()和fsm_search_avail()封裝了自由空間查詢功能和FSM page的結構樹,使得High-level訪問 FSM page看起來像個黑盒。
總結:1.PG在查詢空閒時,先比較root,如果申請的map value比root小,則此頁能滿足,不然申請新heap page。
使用後,修改leaf節點值,以冒泡方式,依次修改父節點以至root節點。
2.VACUUM操作時,修改葉子節點值,再以冒泡方式,依次修改父節點以至root節點。
3.在查詢空閒塊時,會有鎖,尤其是父級page會有share lock;如果是冒泡修改父級page時,會有exclusive lock。
樹形結構在查詢上有優點;但併發上,這也是這種結構帶來的劣勢。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30088583/viewspace-1387176/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL 原始碼解讀(147)- Storage Manager#3(fsm_search函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(146)- Storage Manager#2(fsm_search_avail函式)SQL原始碼AI函式
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- 聊聊dba_temp_free_space的allocated_space和free_space
- PostgreSQL 原始碼解讀(219)- Locks(Overview)SQL原始碼View
- PostgreSQL 原始碼解讀(241)- plpgsql(CreateFunction)SQL原始碼Function
- RxJava2原始碼解讀之 Map、FlatMapRxJava原始碼
- PostgreSQL 原始碼解讀(240)- HTAB簡介SQL原始碼
- PostgreSQL 原始碼解讀(220)- Locks(LOCK Struct)SQL原始碼Struct
- PostgreSQL 原始碼解讀(221)- Locks(PROCLOCK Struct)SQL原始碼Struct
- PostgreSQL 原始碼解讀(1)- 插入資料#1SQL原始碼
- PostgreSQL 原始碼解讀(223)- Locks(Fast Path Locking)SQL原始碼AST
- PostgreSQL 原始碼解讀(224)- Locks(The Deadlock Detection Algorithm)SQL原始碼Go
- PostgreSQL 原始碼解讀(218)- spinlock的實現SQL原始碼
- PostgreSQL 原始碼解讀(244)- plpgsql(CreateFunction-ProcedureCreate)SQL原始碼Function
- PostgreSQL 原始碼解讀(201)- PG 12 BlackholeAM for tablesSQL原始碼
- PostgreSQL 原始碼解讀(152)- PG Tools#4(ReceiveXlogStream)SQL原始碼
- PostgreSQL 原始碼解讀(151)- PG Tools#3(StartLogStreamer)SQL原始碼
- PostgreSQL 原始碼解讀(2)- 插入資料#2(RelationPutHeapTuple)SQL原始碼APT
- PostgreSQL 原始碼解讀(5)- 插入資料#4(ExecInsert)SQL原始碼
- PostgreSQL 原始碼解讀(6)- 插入資料#5(ExecModifyTable)SQL原始碼
- PostgreSQL 原始碼解讀(8)- 插入資料#7(ExecutePlan)SQL原始碼
- PostgreSQL 原始碼解讀(10)- 插入資料#9(ProcessQuery)SQL原始碼
- PostgreSQL 原始碼解讀(13)- 插入資料#12(PostgresMain)SQL原始碼AI
- PostgreSQL 原始碼解讀(217)- A Faster, Lightweight Trigger Function in CSQL原始碼ASTFunction
- PostgreSQL 原始碼解讀(246)- plpgsql(CreateFunction-SearchSysCache3)SQL原始碼Function
- PostgreSQL 原始碼解讀(230)- 查詢#123(NOT IN實現)SQL原始碼
- PostgreSQL 原始碼解讀(222)- Locks(Lock Manager Internal Locking)SQL原始碼
- PostgreSQL 原始碼解讀(245)- plpgsql(CreateFunction-construct_array)SQL原始碼FunctionStruct
- PostgreSQL 原始碼解讀(196)- 浮點數比較SQL原始碼
- PostgreSQL 原始碼解讀(145)- Storage Manager#1(RecordAndGetPageWithFreeSpace)SQL原始碼
- PostgreSQL 原始碼解讀(164)- 查詢#84(表示式求值)SQL原始碼
- PostgreSQL 原始碼解讀(126)- MVCC#10(vacuum過程)SQL原始碼MVCC#
- PostgreSQL 原始碼解讀(225)- Transaction(子事務處理)SQL原始碼
- PostgreSQL 原始碼解讀(215)- 查詢#122(varstrfastcmp_locale)SQL原始碼AST
- PostgreSQL 原始碼解讀(231)- 查詢#124(NOT IN實現#2)SQL原始碼
- PostgreSQL 原始碼解讀(233)- 查詢#126(NOT IN實現#4)SQL原始碼
- PostgreSQL 原始碼解讀(234)- 查詢#127(NOT IN實現#5)SQL原始碼
- PostgreSQL 原始碼解讀(232)- 查詢#125(NOT IN實現#3)SQL原始碼