PostgreSQL 行鎖解讀
像其它資料庫一樣,PostgreSQL資料庫不僅有表級別的鎖,同時也有行級別的鎖。行鎖對於提高系統的並行度至關重要。那麼PostgreSQL是如何實現行鎖的呢?
PostgreSQL獲取行鎖的大致分為以下兩個階段:
1.獲取buffer page級別的鎖
這是一個buffer content鎖,不是單純的buffer pin,當然buffer pin的次數肯定會增加。buffer content鎖分為share和exclusive兩種。”share”是共享鎖,
一般的讀操作,獲取的就是share鎖。”exclusive”是排它鎖,對記錄的修改,增加,刪除等需要獲取此類鎖。
另外Buffer page又分為兩種,分別是local和shared。backend程式獨有的buffer是不需要鎖的,因為它只被本backend程式獨享,是local的。如臨時表等。
我們通常需要加鎖處理都是針對shared型別的buffer,不同程式之間對buffer page的操作需要透過鎖機制來保障。
在對一個buffer page進行加鎖前,需要進行可性性判斷。即本條記錄是否是“HeapTupleInvisible”。如果是invisible的,是不能加鎖,這也是事務隔離的需要。
2.設定行鎖標誌位
行鎖的實現比較複雜,我們不可能把所有需要上鎖的記錄都放到記憶體的lock table中,因為有些情況下,涉及到的記錄非常多。為了解決這個問題,通常只在
tuple的header中設定標記為來標識此行記錄已經被鎖。這兩個關鍵的標記為xmax和infomask。”xmax”放置當前事務的xid,“infomask”放置flag資訊。
設定infomask目的主要是為了區別與正常的deleted tuple分割槽開來,正常情況下xmax是用來標識被刪除的記錄。這樣一來,就不必去維護全域性級別的lock table了,
也可以實現任意記錄數的行鎖操作。另外如果是多個事務同時去上鎖一行記錄,那麼multixact就會被使用。
下面舉例說明:
上圖第一個紅色圈內容為一個事務,事務ID號為:15331854,所執行的語句為:
會話1:
postgres=# begin;
BEGIN
postgres=# update t1 set id=1 where id=2;
UPDATE 1
第二個紅色圈內容為另一個事務,事務ID號為:15331855,所執行的語句為:
會話2:
postgres=# begin;
BEGIN
postgres=# update t1 set id=2 where id=2;
可以看到,第二個會話hang住了,因為他們更新的是同一個表的同一條記錄。
我們再起會話3:
看到這條記錄的xmax已經標記為第一個事務的xid,即:15331854。這也驗證了上面的說法,當update時,PG會去標記每條記錄的xmax,設定為當前xid。
另外一個標記位,從這裡沒有辦法看到。需要dump出這條記錄的header才能看到。
我們再在會話1中跑語句:select xmin,xmax,cmin,cmax ,t.* from t1 t;
細心的同學發現,情況不對,跟前面會話3查出的結果完全不同。那麼是PG錯了嗎?
當然不是的,這就是MVCC實現的結果。會話3中看到的那條記錄是old tuple,也就是老的記錄,因為會話1還沒有提交,而會話1看到的是新的記錄。
根據read commit隔離級別,本事務中之前update掉的記錄,是允許看到的。另外,我們發現xmin的xid已經是本事務的xid了。
總結:
PG對於update其實也生成了一個新版本的tuple,在老版本的tuple header中做了兩個標記:一個是xmax,另外一個是infomask。
“xmax”放持有此記錄lock的xid,infomask存放flag資訊。
infomask的flag資訊如下:
另外對於delete操作和update操作,PG做了不同處理。具體主要表現在索引上。
那麼行鎖與索引有什麼關係? 大家知道PG索引是沒有MVCC的,那麼PG如何處理這些細節呢,下次再詳細講述。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30088583/viewspace-1699315/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL:鎖SQL
- PostgreSQL 併發控制機制(2):表級鎖和行級鎖SQL
- 什麼是鎖?深入分析解讀MySQL鎖,解決幻讀問題!MySql
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- PostgreSQL 原始碼解讀(241)- plpgsql(CreateFunction)SQL原始碼Function
- PostgreSQL死鎖相關SQL
- PostgreSQL 死鎖異常SQL
- PostgreSQL 原始碼解讀(240)- HTAB簡介SQL原始碼
- PostgreSQL 原始碼解讀(219)- Locks(Overview)SQL原始碼View
- PostgreSQL FSM(Free Space Map) 原始碼解讀SQL原始碼
- PostgreSQL 原始碼解讀(15)- Insert語句(執行過程跟蹤)SQL原始碼
- Golang 讀寫鎖RWMutex 互斥鎖Mutex 原始碼詳解GolangMutex原始碼
- 史上最通俗分散式鎖解讀分散式
- PostgreSQL 原始碼解讀(244)- plpgsql(CreateFunction-ProcedureCreate)SQL原始碼Function
- PostgreSQL 原始碼解讀(221)- Locks(PROCLOCK Struct)SQL原始碼Struct
- PostgreSQL 原始碼解讀(1)- 插入資料#1SQL原始碼
- 從自旋鎖、睡眠鎖、讀寫鎖到 Linux RCU 機制講解Linux
- MySQL行鎖、表鎖、間隙鎖,你都瞭解嗎MySql
- 一文搞懂MySQL行鎖、表鎖、間隙鎖詳解MySql
- 多執行緒與併發----讀寫鎖執行緒
- PostgreSQL 原始碼解讀(246)- plpgsql(CreateFunction-SearchSysCache3)SQL原始碼Function
- PostgreSQL 原始碼解讀(220)- Locks(LOCK Struct)SQL原始碼Struct
- PostgreSQL 原始碼解讀(218)- spinlock的實現SQL原始碼
- PostgreSQL 原始碼解讀(10)- 插入資料#9(ProcessQuery)SQL原始碼
- PostgreSQL 原始碼解讀(13)- 插入資料#12(PostgresMain)SQL原始碼AI
- PostgreSQL 原始碼解讀(8)- 插入資料#7(ExecutePlan)SQL原始碼
- PostgreSQL 原始碼解讀(2)- 插入資料#2(RelationPutHeapTuple)SQL原始碼APT
- PostgreSQL的四種程式間鎖SQL
- PostgreSQL之鎖監控指令碼SQL指令碼
- postgresql資料庫鎖介紹SQL資料庫
- 【讀書筆記】Postgresql連線方法及執行器筆記SQL
- PostgreSQL 原始碼解讀(19)- 查詢語句#4(ParseTree詳解)SQL原始碼
- Linux執行緒之讀寫鎖小結Linux執行緒
- PostgreSQL 原始碼解讀(245)- plpgsql(CreateFunction-construct_array)SQL原始碼FunctionStruct
- PostgreSQL 原始碼解讀(224)- Locks(The Deadlock Detection Algorithm)SQL原始碼Go
- PostgreSQL 原始碼解讀(196)- 浮點數比較SQL原始碼
- PostgreSQL 原始碼解讀(5)- 插入資料#4(ExecInsert)SQL原始碼
- PostgreSQL 原始碼解讀(6)- 插入資料#5(ExecModifyTable)SQL原始碼